Fix No Route to Host on Linux

Tested on RHEL 10.2 (Coughlan)
Package iproute 6.17.0-2.el10
firewalld 2.4.3-2.el10_2
curl 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 firewall and service changes (often through console when SSH is blocked)
Scope Diagnose no route to host for any TCP client — ssh, curl, custom ports — using ip route get, neighbor tables, tracepath, and firewall REJECT inspection. Does not replace SSH-only sshd and ListenAddress checks covered in the dedicated SSH troubleshooting guide.
Related guides Fix SSH no route to host
Network is unreachable
Test port connectivity
firewalld cheat sheet
traceroute command

curl https://192.168.56.116 dies with Failed to connect … No route to host while ping 192.168.56.116 still gets replies. That combination usually means the kernel found a route to the IP, but something on the path — often a firewall REJECT on the TCP port — answered with ICMP host unreachable.

Work from the client: confirm the route exists, test the exact TCP port, check neighbors on the same subnet, then inspect REJECT rules on the server.


What no route to host means

Linux maps EHOSTUNREACH to the phrase no route to host on connect(). The name sounds like a missing static route, but the errno also covers:

  • ICMP host unreachable or host prohibited from a router or firewall
  • Neighbor (ARP) resolution failure on a directly connected subnet
  • Local policy routing edge cases where the chosen path cannot forward
Tool Typical message
ssh connect to host … port 22: No route to host
curl Failed to connect … No route to host (curl error 7)
bash /dev/tcp/… connect: No route to host
nc Ncat: No route to host
ping Usually different wording (Destination Host Unreachable after ARP timeout)

Use an IP address first so DNS stays out of the picture. If only hostnames fail, see temporary failure in name resolution.

IMPORTANT
When ip route get prints Network is unreachable with no via line, fix local routes and the default gateway first — that is ENETUNREACH, covered in network is unreachable. This guide assumes a route to the destination IP already exists.

Check the route to the destination

Ask the kernel which interface and source address it would use for the target:

bash
ip route get 192.168.56.116
output
192.168.56.116 dev eth0 src 192.168.56.156 uid 0
    cache

The dev line is the interface packets leave from; src is the source address peers and firewalls see. If this points at the wrong NIC after a VPN connect, fix local policy routing before changing the remote server.

For destinations outside local subnets, confirm a default gateway exists:

bash
ip route show default
output
default via 192.168.56.116 dev eth0 proto static metric 100

When ip route get itself answers RTNETLINK answers: Network is unreachable, stop here and fix routing — the no route to host errors on applications are a consequence of that missing path.


Check gateway reachability

If traffic must leave through a gateway, ping the gateway IP from the same client:

bash
ping -c2 -W2 192.168.56.116
output
PING 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=1.36 ms
64 bytes from 192.168.56.116: icmp_seq=2 ttl=64 time=1.18 ms

--- 192.168.56.116 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms

Replies mean L3 reachability to that IP works. That does not prove every TCP port is open — firewalls filter by protocol and port.

When the gateway does not answer ping, check link state on the client (ip -br link), cable or VLAN membership, and whether the gateway IP is correct for the subnet mask on that interface.


Check ARP and neighbor resolution

On the same broadcast domain, the kernel must resolve the destination MAC address before TCP can flow. Inspect the neighbor cache:

bash
ip neigh show 192.168.56.116

Healthy entry:

output
192.168.56.116 dev eth0 lladdr 08:00:27:c4:4f:20 REACHABLE

REACHABLE means ARP succeeded recently. FAILED or INCOMPLETE on a host that should be up points at L2 problems — wrong VLAN, host powered off, duplicate IP, or a switch port issue — and can produce unreachable errors even when ip route get looks fine.

Clear a stale entry only when you suspect a bad MAC was cached, then retry:

bash
sudo ip neigh del 192.168.56.116 dev eth0

The next packet triggers a fresh ARP request.


Trace where connectivity stops

On a one-hop LAN, tracepath confirms the target responds at L3:

bash
tracepath -n 192.168.56.116
output
1:  192.168.56.116                                        0.111ms reached
     Resume: pmtu 65535 hops 1 back 1

reached on the first hop matches a directly connected host. For multi-hop paths, use traceroute or mtr to see which router returns ICMP unreachable.

TCP failures need a port-level test. Bash can open a socket without extra packages:

bash
timeout 3 bash -c '</dev/tcp/192.168.56.116/443' && echo open || echo failed

When a server firewall REJECTs the client with icmp-host-prohibited, the shell prints:

output
bash: connect: No route to host
bash: line 1: /dev/tcp/192.168.56.116/443: No route to host
failed

The same target with curl command shows the errno in the verbose log:

bash
curl -v --max-time 3 http://192.168.56.116:443
output
* connect to 192.168.56.116 port 443 from 192.168.56.156 port 45228 failed: No route to host
* Failed to connect to 192.168.56.116 port 443 after 2 ms: Could not connect to server
curl: (7) Failed to connect to 192.168.56.116 port 443 after 2 ms: Could not connect to server

Note the client source port line — firewall rules often match source IP, not only destination.


Check firewall REJECT rules

On RHEL-family systems, firewalld can REJECT blocked TCP with ICMP unreachable responses. The client then reports no route to host even though ping and ip route get succeed.

On the server, list the active zone:

bash
sudo firewall-cmd --list-all

Look under services, ports, and rich rules for what is allowed. Rich rules that REJECT a client source are easy to miss:

output
rich rules:
	rule family="ipv4" source address="192.168.56.156" port port="443" protocol="tcp" reject type="icmp-host-prohibited"

That pattern blocks HTTPS from one client IP while SSH from the same host may still work on port 22.

Allow the service permanently on the server zone:

bash
sudo firewall-cmd --permanent --add-service=https

Reload firewalld so the rule is active:

bash
sudo firewall-cmd --reload

Or remove a mistaken REJECT rule:

bash
sudo firewall-cmd --permanent --remove-rich-rule='rule family="ipv4" source address="192.168.56.156" port port="443" protocol="tcp" reject type="icmp-host-prohibited"'

Apply the removal:

bash
sudo firewall-cmd --reload

On any distro, search nftables or iptables for REJECT targets:

bash
sudo nft list ruleset | grep -i reject

reject-with icmp host-prohibited and icmp-host-unreachable commonly map to no route to host on the client. DROP rules tend to cause timeouts instead.

Ports not allowed in the zone may be rejected before traffic reaches the application. Opening the port in the firewall is not the same as running a service — compare with connection refused below.


Verify the fix

Re-run the same TCP check that failed:

bash
timeout 3 bash -c '</dev/tcp/192.168.56.116/443' && echo open || echo failed

After the REJECT rule was removed and HTTPS allowed, the socket opens when a listener is present, or fails with connection refused when the port is open at the firewall but nothing listens.

Confirm neighbors and routing are still healthy:

bash
ip neigh show 192.168.56.116
output
192.168.56.116 dev eth0 lladdr 08:00:27:c4:4f:20 REACHABLE

The routing decision should still name the same outbound interface:

bash
ip route get 192.168.56.116
output
192.168.56.116 dev eth0 src 192.168.56.156 uid 0
    cache

For SSH-specific verification (sshd, ListenAddress, keys), continue with Fix SSH no route to host once TCP port 22 connects.


No route to host vs connection refused

Both errors appear before application data flows, but the fix differs:

Message errno Route in ip route get Typical cause
No route to host EHOSTUNREACH Often shows dev / via Firewall REJECT with ICMP unreachable, ARP failure, upstream ICMP
Connection refused ECONNREFUSED Shows dev / via Port allowed through firewall but no listener, or TCP RST from host
Network is unreachable ENETUNREACH Fails with RTNETLINK Missing default route or no matching prefix
Connection timed out May show route Silent DROP along path

Demonstration on the same server IP: with the firewall allowing port 59999 but no process listening, the client sees refused:

bash
timeout 3 bash -c '</dev/tcp/192.168.56.116/59999' 2>&1
output
bash: connect: Connection refused
bash: line 1: /dev/tcp/192.168.56.116/59999: Connection refused

With the port blocked by REJECT instead, the same client IP gets no route to host on port 443 — fix the firewall rule, not the application daemon.


Troubleshooting

Symptom Likely cause Fix
Ping OK; TCP fails with no route to host firewalld / nftables REJECT on that port or source IP Allow service/port; remove REJECT rich rules
ip route get OK; TCP fails Same as above, or ARP FAILED ip neigh show; fix L2/VLAN; adjust firewall
ip route get → Network is unreachable No route to destination network Fix default gateway / routes
Works from some clients only Source-based zone or rich rule Compare client src from ip route get with firewall-cmd --list-rich-rules
nc / curl timeout (not no route) DROP rule or dead path mid-network tracepath / traceroute; check intermediate filters
SSH no route to host after OS hardening SSH service dropped from zone firewall-cmd --add-service=ssh; see SSH guide for sshd
After VPN connect Traffic exits wrong interface Policy routing / split tunnel; fix ip route get source

References


Summary

No route to host is an EHOSTUNREACH error at the socket layer. It does not always mean your routing table is empty — on many Linux servers the message appears when a firewall REJECTs TCP with ICMP host prohibited while ICMP echo still passes.

Start with ip route get and a port-specific test (bash /dev/tcp, nc, or curl -v). If the route looks correct and ping works, read ip neigh for ARP problems, then inspect firewalld rich rules or nftables REJECT entries that match your client source IP and destination port.

Connection refused on the same IP means the packet reached the host and nothing accepted the socket — open the service or fix the listener. Network is unreachable means the kernel never found a route — fix gateways first. Once TCP connects for SSH, hand off to Fix SSH no route to host for sshd and authentication checks.


Frequently Asked Questions

1. Does no route to host always mean the routing table is wrong?

No. Linux returns EHOSTUNREACH when the kernel or a remote device reports host unreachable. A correct route in ip route get plus ping success can still produce no route to host on TCP when a firewall REJECTs the port with an ICMP unreachable response.

2. Why does ping work but curl shows no route to host?

Ping uses ICMP. curl and ssh use TCP on a specific port. A firewall can allow echo-request while REJECT-ing HTTPS or SSH, which surfaces as no route to host on many Linux firewalls including firewalld with icmp-host-prohibited.

3. How is no route to host different from connection refused?

No route to host means the TCP handshake never completed because the kernel saw an unreachable condition. Connection refused means the packet reached the host and nothing accepted the connection, or the host sent TCP RST back.

4. How is no route to host different from network is unreachable?

Network is unreachable means no local route exists for the destination network. No route to host usually means a route was selected but neighbor resolution failed or an intermediate firewall or router returned ICMP host unreachable.

5. Which tools show EHOSTUNREACH the same way?

ssh, curl, wget, bash /dev/tcp/host/port, and nc often print no route to host for the same underlying errno. ip route get still prints a via or dev line when a local route exists, which helps separate routing-table gaps from firewall REJECT.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)