Diagnosing "Connection refused"
What Does "Connection refused" Mean?
Conclusion: The remote host is reachable, but it actively rejected the connection on that port. It is not "unreachable" — it arrived and was turned away. The usual cause is that no service is listening there.
Connection refused appears when a TCP connection request (SYN) is answered with a RST (reset) from the other end. In other words, the packet did reach the host. The host itself — or a device in front of it — explicitly replied "this port will not accept connections".
$ curl http://192.0.2.10:8080 curl: (7) Failed to connect to 192.0.2.10 port 8080 after 3 ms: Connection refused
$ ssh user@192.0.2.10 ssh: connect to host 192.0.2.10 port 22: Connection refused
At the system-call level this is the error ECONNREFUSED, which apps surface as "Connection refused". The reply comes back immediately (a few milliseconds), and that speed is the key difference from a timeout, discussed next.
Prerequisites
- OS: Ubuntu / a typical Linux
- Target: a service listening over TCP (SSH / web / DB, etc.)
- We assume you can get a shell on both client and server
How Is "Connection refused" Different from a Timeout?
Conclusion: Refused returns a RST instantly (the host is alive); a timeout returns nothing (packets are being dropped). That single difference splits the cause into "service side" versus "network path".
The first thing to settle is whether you were rejected or met with silence. Tell them apart by the message and the time to respond.
| Symptom | What comes back | Main causes |
|---|---|---|
| Connection refused | TCP RST (instant) | Service down / wrong port / REJECT rule |
| Connection timed out | No response (long wait) | DROP firewall / broken path / host down |
$ time nc -zv 192.0.2.10 22
nc: connect to 192.0.2.10 port 22 (tcp) failed: Connection refused real 0m0.004s
If the failure returns in 0.0xx seconds, it is refused (the host is responding). If it hangs for ten-plus seconds before failing, it is a timeout — suspect a DROP firewall or a path problem. This article covers the refused side; for timeout-leaning triage see Port Connectivity.
Refused means "the host is alive but the port turned me away". Whether ping works is not a reliable signal (ICMP and TCP are separate; SSH can succeed even when ping fails).
Why Does "Connection refused" Happen?
Conclusion: Nine times out of ten, nothing is listening on the target port. The cause reduces to four things — service down, wrong port, wrong listen address, or a REJECT rule — and working top to bottom is fastest.
The paths that produce refused, organized by cause:
| Cause | When it happens | Where to start |
|---|---|---|
| Service is stopped | Crashed / failed to start / not up after a reboot | systemctl status |
| Wrong port number | Config change, listening on a non-default port | ss -tlnp |
| Wrong listen address | Bound to 127.0.0.1, unreachable from outside |
ss -tlnp |
| Firewall REJECT | nftables/iptables actively rejects with RST/ICMP | ss + rule check |
The reliable starting point is checking on the server whether anything is actually listening. The client-side error alone cannot tell a stopped service from a wrong port.
How Do You Check Whether the Service Is Up?
Conclusion: On the server, run
ss -tlnpand confirm the target port is in LISTEN. If it is missing, the service is down or the port is wrong. Confirm the state and reason withsystemctl statusandjournalctl.
Log into the server and list the listening ports.
$ sudo ss -tlnp
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=812,fd=3))
LISTEN 0 511 127.0.0.1:8080 0.0.0.0:* users:(("node",pid=1043,fd=18))
The ss options are -t (TCP), -l (LISTEN only), -n (numeric, no name resolution), -p (show the process, needs root). If the target port is not in this list, nothing is listening there, and the client sees an immediate refused.
When the port is absent, check the corresponding service.
$ systemctl status nginx
× nginx.service - A high performance web server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled)
Active: failed (Result: exit-code) since ...
Active: failed or inactive (dead) means it is stopped. Try to start it, and if it fails, follow the reason in the logs.
$ sudo systemctl start nginx $ journalctl -u nginx -n 30 --no-pager
If refused persists while the service is clearly up, it is almost always a mismatched listen address or port. Move to the next section.
The Listen-Address Trap (the 127.0.0.1 Problem)
Conclusion: A service bound to
127.0.0.1:portis reachable from the same server but always refused from outside. Always check whether the Local Address column inss -tlnpis127.0.0.1or0.0.0.0(or::).
This is the classic "the service is running but I can't reach it from outside" case. Look at the earlier output again.
LISTEN 0 128 0.0.0.0:22 ... sshd LISTEN 0 511 127.0.0.1:8080 ... node
0.0.0.0:22→ listening on all interfaces. Reachable from outside.127.0.0.1:8080→ loopback only.curl localhost:8080on the server works, but anything external or from another host is refused.
If it succeeds on the server and is refused from outside, this is almost certainly the cause. Change the app's bind address (often a bind / listen / host setting) to 0.0.0.0 or the target IP, then restart.
# Succeeds on the server (loopback reaches it) $ curl -sS http://127.0.0.1:8080/ >/dev/null && echo OK # Refused from outside / another host $ curl http://192.0.2.10:8080/ curl: (7) Failed to connect ... Connection refused
Databases (PostgreSQL / MySQL, etc.) often bind to 127.0.0.1 by default. Opening them to external connections must be done together with a review of authentication and firewalling — do not just open them to 0.0.0.0.
When a Firewall Is the Cause (REJECT vs DROP)
Conclusion: A firewall set to
REJECTreturns RST/ICMP, producing Connection refused;DROPdiscards the packet, producing a timeout. If you see refused, suspect an explicit REJECT rule.
A firewall can deny traffic two ways, and the symptom on the client differs.
- REJECT: explicitly signals the denial (TCP RST or ICMP port-unreachable) → the client gets an immediate
Connection refused - DROP: silently discards the packet → the client waits and gets a
timeout
So when you see refused, a DROP-style firewall (ufw's default deny is DROP) is usually not the culprit. Still, check for an explicit REJECT rule.
# Inspect nftables rules $ sudo nft list ruleset | grep -i -E 'reject|dport' # On systems using iptables $ sudo iptables -L -n -v --line-numbers
Chain INPUT (policy ACCEPT) num target prot ... destination 1 REJECT tcp ... tcp dpt:8080 reject-with tcp-reset
If a REJECT ... reject-with tcp-reset rule matches that port, it is the source of the refused. Decide whether the rule is needed, and remove it if not. If you use ufw, see ufw SSH Troubleshooting for confirming and restoring allow rules.
Shortcut: if a loopback connection on the server (curl 127.0.0.1:port) works and only outside access is refused, the cause is the listen address or the firewall. If it is refused even on the server, narrow it to a stopped service or wrong port.
How to Triage from the Client Side
Conclusion: When you cannot get onto the server, use
nc -zvto test reachability only and tell refused from timeout.ss -tnalso shows how far the handshake got.
When you cannot immediately reach the server, do a minimal check from the client.
# Test only whether the port connects (-z: no data sent, -v: verbose) $ nc -zv 192.0.2.10 22
If Connection refused returns instantly, the host is responding but the port is closed. If it timed out, suspect the path or a DROP firewall, and go to Port Connectivity rather than this article.
Looking at the TCP state after a connection attempt shows how far the handshake got.
$ ss -tn dst 192.0.2.10
If it stays in SYN-SENT, no response came back (timeout family). With refused the connection never establishes and fails immediately.
Run port scans and reachability checks only against hosts you own or are authorized to test. Avoid scanning third-party hosts without permission.
Checklist When It Still Fails
Conclusion: Refused confirms "host alive, port rejecting". Work through service → port → listen address → REJECT rule, and the cause collapses to one of those four.
- [ ] Did you tell
refused(instant) fromtimed out(long wait)? - [ ] On the server, did
ss -tlnpshow the target port in LISTEN? - [ ] If no LISTEN, did you check the stop reason with
systemctl status/journalctl -u? - [ ] Is the Local Address
127.0.0.1(external access needs0.0.0.0etc.)? - [ ] Does the port number match on the client and the listener?
- [ ] Is there a REJECT rule for that port in
nft list ruleset/iptables -L? - [ ] Does a server-side loopback (
curl 127.0.0.1:port) work (if so, the cause is outside)?