| Tested on | RHEL 10.2 (Coughlan) — vm1.lab.example (192.168.56.116) as server; client checks run against that IP from the same LAN |
|---|---|
| Package | iproute 6.17.0-2.el10httpd 2.4.63-13.el10_2.5firewalld 2.4.3-2.el10_2nmap-ncat 7.92-5.el10curl 8.12.1 |
| Applies to | Ubuntu, Debian, Kali Linux, Linux Mint, Pop!_OS, Raspberry Pi OS, elementary OS, Zorin OS, Parrot OS, MX Linux, RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, Fedora, Arch Linux |
| Privilege | Normal user on the client for diagnostics; sudo or root on the server for systemctl, ss, and firewall changes |
| Scope | Diagnose connection refused for any TCP client — ssh, curl, web ports, custom services — using ping, systemd, ss, bind-address checks, and firewalld. Contrasts refused with timeout and no route to host. Does not replace SSH key or sshd_config authentication troubleshooting. |
| Related guides | No route to host Network is unreachable Test port connectivity firewalld cheat sheet curl command |
curl http://192.168.56.116 dies with Connection refused while ping 192.168.56.116 still gets replies. The host is up and routed — the failure is on the TCP port: nothing accepted the connection, or the daemon listens somewhere your client cannot reach.
Work from the client to confirm reachability, then on the server check the service, listening sockets, bind address, and firewall before you retest with nc or curl.
What connection refused means
Linux maps ECONNREFUSED to connection refused on connect(). The packet reached the destination IP; the kernel or a listener sent TCP RST because no process accepted that port.
| Tool | Typical message |
|---|---|
ssh |
connect to host … port 22: Connection refused |
curl |
Failed to connect … Connection refused (curl error 7) |
bash /dev/tcp/… |
connect: Connection refused |
nc |
Ncat: Connection refused |
ping |
Usually succeeds — ICMP is not the same port check |
Use a literal IP first so DNS stays out of the picture. If only hostnames fail while IP ping works, see Linux can ping IP but not hostname.
ip route get answers Network is unreachable, fix routes first — that is network is unreachable. When the client prints no route to host while ping works, inspect firewall REJECT rules in no route to host before you restart services.
Confirm the server is reachable
Ping the server IP from the client. Skip hostnames so you separate L3 reachability from DNS:
ping -c2 -W2 192.168.56.116PING 192.168.56.116 (192.168.56.116) 56(84) bytes of data.
64 bytes from 192.168.56.116: icmp_seq=1 ttl=64 time=0.056 ms
64 bytes from 192.168.56.116: icmp_seq=2 ttl=64 time=0.072 ms
--- 192.168.56.116 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1035msReplies mean the host answers at the IP layer. That does not prove any TCP port is open.
Confirm the kernel would route to that address the same way your application does:
ip route get 192.168.56.116local 192.168.56.116 dev lo src 192.168.56.116 uid 0
cache <local>A dev or local line means a route exists. If this command fails with Network is unreachable, stop here and fix routing before chasing daemons.
Check whether the service is running
Connection refused on port 80 often means the web server is stopped even though SSH on port 22 still works. On the server, check the unit you expect to own the port — here httpd for HTTP:
sudo systemctl status httpd --no-pagerWhen the service is healthy, the active line shows running:
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; preset: disabled)
Active: active (running) since Sat 2026-08-22 08:55:14 IST; 2min agoStop the service to reproduce the error clients see:
sudo systemctl stop httpdFrom the client, retry HTTP against the same IP:
curl -v --connect-timeout 3 http://192.168.56.116/* Trying 192.168.56.116:80...
* connect to 192.168.56.116 port 80 from 192.168.56.116 port 42818 failed: Connection refused
* Failed to connect to 192.168.56.116 port 80 after 0 ms: Could not connect to server
curl: (7) Failed to connect to 192.168.56.116 port 80 after 0 ms: Could not connect to serverImmediate refusal with ping still working points at a stopped or crashed daemon — not cable loss. Bring the unit back before you move on:
sudo systemctl start httpdsystemctl start exits silently when the unit enters active (running); confirm with systemctl is-active httpd, which should print active.
The same pattern applies to sshd on port 22: stopping sshd makes ssh print connection refused even when the host still answers ping.
Check listening ports with ss
ss shows which addresses and ports have listeners. On the server, filter for the port your client uses:
ss -tlnp | grep ':80'With httpd running, Apache binds all interfaces on port 80:
LISTEN 0 511 *:80 *:* users:(("httpd",pid=14951,fd=4),("httpd",pid=14953,fd=4),("httpd",pid=14955,fd=4),("httpd",pid=14957,fd=4))The *:80 local address means any IPv4 client can connect when the firewall allows it. No line for that port while the service claims to be up means the process has not opened the socket yet — check logs with journalctl -u httpd -e.
For SSH, confirm port 22 is listening:
ss -tlnp | grep ':22'LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=15217,fd=7))
LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=15217,fd=8))If clients target port 2222 but ss only shows :22, fix the client port or change Port in sshd_config and restart sshd.
Check the service bind address
A listener on 127.0.0.1 accepts only local connections. Remote clients hit the host IP and get connection refused even when a process owns the port locally.
Open port 8888 in the firewall first so filtering does not mask the bind issue:
sudo firewall-cmd --permanent --add-port=8888/tcpReload firewalld so the rule is active:
sudo firewall-cmd --reloadStart a test listener on loopback only:
nc -l 127.0.0.1 8888 >/dev/null &Verify the socket is loopback-scoped:
ss -tlnp | grep ':8888'LISTEN 0 10 127.0.0.1:8888 0.0.0.0:* users:(("nc",pid=15147,fd=5))Local clients can connect to loopback:
timeout 3 bash -c '</dev/tcp/127.0.0.1/8888' && echo openopenThe same port on the LAN IP is refused because nothing listens on that address:
timeout 3 bash -c '</dev/tcp/192.168.56.116/8888' 2>&1bash: connect: Connection refused
bash: line 1: /dev/tcp/192.168.56.116/8888: Connection refusedFix ListenAddress in the service config — for SSH, /etc/ssh/sshd_config should use 0.0.0.0 or the specific NIC IP, not only 127.0.0.1. Remove the test port and stop the background nc when you are done:
sudo firewall-cmd --permanent --remove-port=8888/tcpReload firewalld so the removal takes effect:
sudo firewall-cmd --reloadCheck firewall rules
Firewalls can block before traffic reaches a listener. On RHEL-family systems, list the active zone on the server:
sudo firewall-cmd --list-allThe services and ports lines show what is allowed. HTTP and SSH are already open in this lab zone:
services: cockpit dhcp dhcpv6-client dns http https nfs ssh tftp
ports: 1313/tcpA DROP rule drops packets without RST, which clients usually report as timeout — not refused. Add a direct DROP on port 9443 to demonstrate the difference:
sudo firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -p tcp --dport 9443 -j DROPApply the DROP rule:
sudo firewall-cmd --reloadFrom the client, a short timeout on /dev/tcp hangs until it expires:
timeout 5 bash -c '</dev/tcp/192.168.56.116/9443' 2>&1; echo exit=$?exit=124exit=124 means the timeout command ended the wait — classic silent DROP behavior.
Remove the test DROP rule when finished:
sudo firewall-cmd --permanent --direct --remove-rule ipv4 filter INPUT 0 -p tcp --dport 9443 -j DROPReload again so the DROP rule disappears:
sudo firewall-cmd --reloadOn this host, blocked ports without a listener can also return connection refused immediately. When ping works but TCP fails with no route to host instead, read no route to host for REJECT rich rules. Opening the firewall does not start the service — you still need a listener in ss.
Verify the port with nc or curl
After the service is running and the firewall allows the port, confirm from the client with a one-shot TCP check:
timeout 3 bash -c '</dev/tcp/192.168.56.116/80' && echo openopennc prints an explicit result for the same test:
nc -zv -w3 192.168.56.116 80Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Connected to 192.168.56.116:80.
Ncat: 0 bytes sent, 0 bytes received in 0.02 seconds.curl exercises the application layer when HTTP or HTTPS is in scope:
curl -sS -o /dev/null -w 'http_code=%{http_code}\n' --connect-timeout 3 http://192.168.56.116/http_code=403HTTP 403 means TCP connected and Apache answered — connection refused is gone. The status code itself is a separate authorization or index issue.
For a port that is allowed through the firewall but has no daemon, the client still gets refused:
sudo firewall-cmd --permanent --add-port=59999/tcpReload so the open port is live before you probe it:
sudo firewall-cmd --reloadWith the firewall open and no listener, nc should report refused immediately:
nc -zv -w3 192.168.56.116 59999 2>&1Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Connection refused.Clean up the test port:
sudo firewall-cmd --permanent --remove-port=59999/tcpReload to drop the temporary test port:
sudo firewall-cmd --reloadConnection refused vs timeout
Both errors happen before application data flows, but the fix differs:
| Message | errno / behavior | Ping to same IP | Typical cause |
|---|---|---|---|
| Connection refused | ECONNREFUSED, immediate RST |
Often works | Service down, wrong port, bind to 127.0.0.1 only |
| Connection timed out | No TCP reply until timer | May work | Firewall DROP, filtered path, wrong IP |
| No route to host | EHOSTUNREACH |
Often works | Firewall REJECT with ICMP unreachable — see no route to host |
| Network is unreachable | ENETUNREACH |
Fails for remote targets | Missing default route — see network is unreachable |
Demonstration on the same server IP with httpd stopped:
timeout 3 bash -c '</dev/tcp/192.168.56.116/80' 2>&1bash: connect: Connection refused
bash: line 1: /dev/tcp/192.168.56.116/80: Connection refusedWith a DROP rule on port 9443, the same client waits until timeout kills the attempt — compare that delay with the instant RST above.
Wrong SSH port while sshd listens on 22 produces the same immediate refusal:
ssh -o ConnectTimeout=3 -p 2222 root@192.168.56.116 exit 2>&1ssh: connect to host 192.168.56.116 port 2222: Connection refusedTroubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Ping OK; TCP refused on one port | Service stopped or wrong port | systemctl start unit; match client port to ss -tlnp |
| Ping OK; refused only from remote clients | Listener on 127.0.0.1 |
Set ListenAddress 0.0.0.0 or NIC IP; restart daemon |
ss shows *:port but remote refused |
Firewall or SELinux | firewall-cmd --add-service or --add-port; check ausearch if enforcing |
| Refused on every port including SSH | sshd down or host is wrong IP |
systemctl start sshd; verify target IP with ip addr on server |
| Hangs then timeout, not refused | DROP rule or dead path | nft list ruleset | grep -i drop; compare with test port connectivity |
| No route to host (not refused) | REJECT with ICMP | Allow port in firewalld; see no route to host |
ip route get → Network is unreachable |
Missing route | Fix default gateway / routes |
| Hostname fails; IP works | DNS, not TCP port | Linux ping IP but not hostname |
References
- ss(8) — socket statistics and listening ports
- systemd.service(5) — service unit state
- firewalld.richlanguage(5) — REJECT and DROP behavior
- errno(3) —
ECONNREFUSEDand related codes - curl(1) — verbose connection errors
Summary
Connection refused means the packet reached the host and nothing accepted your TCP port — ECONNREFUSED at the socket layer. Ping can succeed while curl, ssh, or nc fail because ICMP does not prove a listener exists on port 80, 443, or 22.
Start on the client with ping and ip route get so you know routing is not the blocker. On the server, match systemctl status and ss -tlnp to the port your client uses, then check whether the daemon binds only to 127.0.0.1. Open the port in firewalld or nftables when filtering is in play, and retest with bash /dev/tcp, nc -zv, or curl -v.
Instant refusal with a live ping usually means start the service or fix the bind address. A long hang points at DROP or network loss — not the same fix. When the message is no route to host or network is unreachable instead, switch to the sibling guides for firewall REJECT and missing routes before you chase application logs.

