SSH "Connection Timed Out" on Port 22 — and the Firewall Chain Test

Timeout (not refused) means packets are silently dropped: firewall, security group, wrong IP, or sshd down behind a DROP policy. A three-hop test finds which layer is eating it.

What you'll see

Root causes

Cloud security group / firewall dropping 22

Provider security groups default-drop: 22 open only to your IP, or not at all. This is the single most common cause of timeout-vs-refused on cloud hosts.

Wrong IP or host not up

DHCP changes, wrong elastic-IP association, or the box is down entirely. ping/other-port tests distinguish 'host unreachable' from 'port filtered'.

ISP or local network blocking outbound 22

Some corporate/hotel networks block outbound 22. Test from another network (mobile hotspot) — instant differential.

Fix it

  1. Test whether the host is alive at all
    ping -c 3 <host> ; curl -s --max-time 5 http://<host>:<other-open-port>/ -o /dev/null -w '%{http_code}\n'
  2. Check the port from outside
    nc -zv -w 5 <host> 22 2>&1 ; # timeout = filtered; refused = closed but reachable; open = sshd answer
  3. Fix the security group / firewall rule (scoped, not wide open)
    # allow 22 from your IP only: e.g. aws ec2 authorize-security-group-ingress --group-id sg-xxx --protocol tcp --port 22 --cidr <your-ip>/32
  4. If outbound 22 is blocked locally: use ssh over 443 or a bastion
    ssh -p 443 user@host   # if sshd also listens on 443; or ssh -J jumpuser@bastion user@target

Field note

Timeout vs refused is your diagnostic: refused = host reachable, port closed (a config); timeout = something drops packets (firewall/route). Keep security groups IP-scoped — 0.0.0.0/0 on 22 earns you a permanent brute-force chorus in the logs.

Common questions

Why timeout instead of 'connection refused'?

Refused is an active RST: the host answered and said the port's closed. Timeout is silence: a firewall, security group, or dead host dropped the packets. The fixes are entirely different.

SSH worked yesterday from this machine. What changed?

Your public IP changed (most common for IP-scoped rules), the host's IP changed, or the network you're on blocks 22. Check the security group allows your current IP: curl -s ifconfig.me

Ship it right the first time

Our most-documented failures, packaged as ready-to-ship starter kits: Docker, Kubernetes, and Terraform.

Browse the template store →

One-time. Yours to modify. Instant download from the NinjaOps template store.