| Tested on | RHEL 10.2 (Coughlan) — vm2.lab.example (192.168.56.220, connects to vm1.lab.example from source 192.168.56.156) as SSH client; vm1.lab.example (192.168.56.116) as SSH server |
|---|---|
| Package | openssh-clients 9.9p1-25.el10_2, openssh-server 9.9p1-25.el10_2, and firewalld on the server |
| Applies to | RHEL, Rocky Linux, AlmaLinux, Fedora, Ubuntu, Debian, and other Linux systems with OpenSSH |
| Privilege | Normal user on the client; sudo or root on the server for firewall and sshd checks (often via console when SSH is down) |
| Scope | Interpreting No route to host for SSH, TCP reachability tests, local routing with ip route get, remote sshd and ListenAddress, and server firewalls (firewalld, nftables, ufw). Does not replace testing SSH end to end or cannot assign requested address on the server bind side. |
| Related guides | ssh command Test SSH connection firewalld cheat sheet ss command traceroute command |
ssh: connect to host … port 22: No route to host looks like a routing failure, but on Linux it often appears when a firewall REJECTs your TCP connection with an ICMP unreachable message. The wording is generic; the fix depends on whether the path, the port, or sshd itself is wrong.
There is no single switch that fixes every case. Work from the client first (can you open a TCP socket?), then routing and neighbor checks, then the server firewall. If the error becomes connection refused, check sshd on the server through the console or another out-of-band path.
The lab examples use vm2.lab.example reaching vm1.lab.example at 192.168.56.116. Your client may show a different source address than its primary hostname — check with ip route get <server-ip> before writing firewall rules.
What the error actually means
The OpenSSH client reports whatever errno the kernel returns from the TCP connect. No route to host (EHOSTUNREACH) means the kernel received or generated a host-unreachable condition while trying to connect. That can come from local routing, neighbor resolution, or an ICMP unreachable returned by another device or firewall — not from SSH authentication failure.
Linux maps both local routing or neighbor state and ICMP host-unreachable messages from remote routers or firewalls to the same errno on connect().
Common causes:
- No usable route or gateway for the destination network
- Same-subnet ARP failure (host down, wrong VLAN, duplicate IP)
- A router or firewall returning ICMP host/network unreachable
- A local or remote firewall REJECT rule (very common for SSH on RHEL-family systems with
firewalld)
Do not assume the routing table is wrong until you rule out a REJECT on port 22.
Compare SSH connection errors
The message tells you which layer failed first:
| Client message | Typical meaning | Server log useful? |
|---|---|---|
No route to host |
ICMP unreachable or local unreachable before TCP handshake completes | Usually no — packet may never reach sshd |
Connection refused |
The TCP connection was actively refused — commonly because nothing is listening on that port, though a firewall can also reject with a reset | Sometimes — check if sshd is down, bound elsewhere, or a firewall sent RST |
Connection timed out |
Silent DROP along the path, or host not answering at L3/L4 | Rarely |
Network is unreachable |
No usable route to the destination network | No |
On the lab client, blocking sshd on the server produced connection refused, while a firewalld rich rule with reject type="icmp-host-prohibited" for the client source produced no route to host for the same target IP.
Test TCP reachability to the SSH port
Start with a plain TCP check to the SSH port (default 22). This avoids guessing from ping alone.
On the client, Bash can open /dev/tcp without extra packages:
timeout 3 bash -c '</dev/tcp/192.168.56.116/22' && echo open || echo failedWhen a lab firewall REJECT rule blocked the client source, the shell reported:
bash: connect: No route to host
bash: line 1: /dev/tcp/192.168.56.116/22: No route to host
failedWhen sshd was stopped but the network path was open, OpenSSH reported connection refused instead — a different failure mode.
If you prefer netcat for port checks, use:
nc -zv -w 3 192.168.56.116 22A non-zero exit or No route to host here means the problem is still below SSH — fixing keys or sshd_config on the server will not help yet.
Check the local route to the server
Confirm the client knows how to reach the server IP:
ip route get 192.168.56.116Sample output from the lab client:
192.168.56.116 dev eth0 src 192.168.56.156 uid 0
cacheThe line names the outbound interface (eth0), the source address the kernel will use (192.168.56.156), and the direct path to the host. If this fails or points at the wrong interface (common with VPNs or multiple NICs), fix local routing before touching the server.
For remote networks, also verify a default gateway exists:
ip route show defaultWhen the destination is several hops away, traceroute or mtr shows where packets stop — useful when a gateway returns ICMP unreachable.
On the same subnet, check neighbor resolution when the host should be directly reachable:
ip neigh show 192.168.56.116A FAILED or incomplete entry can trigger host-unreachable errors even when the IP looks correct on paper.
Check the server firewall (common cause)
On RHEL-family systems, firewalld can REJECT blocked traffic with ICMP unreachable responses, which may surface as no route to host on the client — even though ping still works.
List the active zone and allowed services:
firewall-cmd --list-allEnsure the SSH service (or your custom port) is allowed for clients that need access:
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reloadIn the lab, adding a rich rule that REJECTs the client source with icmp-host-prohibited reproduced the exact SSH error:
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.56.156" service name="ssh" reject type="icmp-host-prohibited"'
sudo firewall-cmd --reloadFrom the client, SSH then failed with:
ssh: connect to host 192.168.56.116 port 22: No route to hostRemoving that rule and reloading firewalld restored access. Check for:
- Missing
sshservice in the zone attached to the server interface - Rich rules that match your client source IP (not just the destination)
- A separate source-based zone (for example NFS) that overrides
publicfor specific clients — those clients can lose SSH while others still connect
On Ubuntu with ufw, verify Status: active and that OpenSSH or your port is allowed. On any distro, inspect nftables/iptables REJECT rules:
sudo nft list ruleset | grep -i rejectLook for reject-with icmp host-prohibited or icmp-host-unreachable. REJECT differs from DROP: DROP tends to cause timeouts; REJECT often produces no route to host.
Avoid flushing entire firewall tables in production. Add explicit allow rules, or temporarily move the client into a trusted source list while you test.
If the error changes to Connection Refused
When TCP tests return connection refused instead of no route to host, the TCP connection was actively refused — commonly because nothing is listening on the SSH port, though a firewall can also reject with a reset. Check sshd and its listen settings first; if those look correct, inspect firewall rules that send TCP RST.
Run these on the server through the hypervisor console, IPMI, or provider shell when SSH is down.
Check the unit:
systemctl status sshdConfirm something listens on the SSH port (22 unless you changed it):
ss -ntlp | grep ':22'Sample output when sshd is healthy:
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1241,fd=7))
LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=1241,fd=8))Read the effective server settings (merged drop-ins), not just the file on disk:
sshd -T | grep -E '^(port|listenaddress) 'Sample output:
port 22
listenaddress [::]:22
listenaddress 0.0.0.0:220.0.0.0:22 means all IPv4 addresses. A narrow listenaddress 10.0.0.5:22 accepts SSH only on that IP — connections to other addresses fail even when the service is running. Match the address you use in ssh user@….
Read ssh -vvv on the client
Verbose SSH still helps confirm where the client stops:
ssh -vvv -o ConnectTimeout=5 user@192.168.56.116When the network layer fails first, you see the TCP connect error immediately and no server banner or key exchange lines. That pattern means sshd logs on the server (journalctl -u sshd) stay quiet — the session never arrived.
Also review client-side config that might force the wrong address, port, or jump host:
ssh -G 192.168.56.116 | grep -E '^(hostname|port|user|proxyjump) 'Files to check: ~/.ssh/config, /etc/ssh/ssh_config, and drop-ins under ssh_config.d.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
No route to host but ping works |
Remote or local firewall REJECT on TCP 22 (or your SSH port) | Allow ssh service or port on the server zone; remove source-specific REJECT rich rules |
Connection refused to port 22 |
sshd stopped or not listening on that IP/port |
systemctl start sshd; verify with ss -ntlp and sshd -T |
| Works from some clients only | Source-based firewalld zone or rich rule | firewall-cmd --get-active-zones; compare failing client source IP with ip route get |
No route to host to every port |
Wrong route, down interface, or ARP failure | ip route get, ip link, ip neigh; fix L2/L3 before SSH |
Network is unreachable |
No route to destination network | Check ip route get and the default/static routes; correct the route or gateway configuration |
| Local SSH OK, remote fails | Host firewall or upstream filter | Test TCP from remote client; inspect REJECT rules |
After changing sshd_config |
Service not reloaded or ListenAddress too narrow |
sshd -T for effective values; systemctl reload sshd |
References
- ssh(1) — OpenSSH client
- sshd(8) — OpenSSH server
- ip-route(8) — routing table management
- firewalld.richlanguage(5) — rich rule syntax including REJECT types
- RFC 792 — ICMP — unreachable message types
Summary
SSH no route to host is a network-layer error, not an authentication problem. The name is misleading: Linux can return EHOSTUNREACH from local routing or neighbor state, or from an ICMP unreachable a firewall or router sends back — not only when the routing table lacks a path.
Follow the decision tree in order: test the SSH port with /dev/tcp or nc, run ip route get and ip neigh, inspect the server firewall for REJECT rules (especially when ping works but SSH does not), and only then — if the error is connection refused — check sshd and ListenAddress on the server console.
Once TCP connects, continue with SSH connection testing for keys, host keys, and auth. If the server fails at bind time with a local address error, see cannot assign requested address — a different failure than no route to host from the client.

