You run ssh user@server, and... nothing. The cursor just sits there. Thirty seconds later:
ssh: connect to host 203.0.113.10 port 22: Operation timed out
That long hang is the clue. Unlike "Connection refused," which fails instantly, a timeout means your connection attempt vanished into the void — it never got any response from the server at all.
Here's how to track down where your packets are disappearing.
Timed out vs. refused — they mean opposite things
Get this distinction right and you've already cut the problem in half:
- Operation timed out (hangs ~30s, then fails) — your packets never reached a listening service. Something is silently dropping them: a firewall, a wrong address, or a network block.
- Connection refused (instant) — you did reach the machine, but nothing accepted the connection.
A timeout almost always means a firewall dropping packets or you're aiming at the wrong place.
Step 1: Verify the IP address is correct
The single most common cause is a stale IP. Cloud instances on AWS, GCP, and Azure usually get a new public IP every time they're stopped and started.
Check the current public IP in your provider's dashboard, then make sure that's what you're connecting to. If you use a hostname:
dig +short server.example.com
Confirm that resolves to the IP you expect. An out-of-date DNS record, or a stale HostName in ~/.ssh/config, sends you to a dead address that silently drops everything.
Step 2: Check the cloud provider firewall
This is the number-one cause for cloud servers. Every major provider has a network firewall outside the OS that drops traffic before it ever reaches the machine:
- AWS → Security Groups (and Network ACLs)
- Google Cloud → VPC firewall rules
- Azure → Network Security Groups
- Oracle Cloud → security lists / NSGs
- DigitalOcean / Hetzner → Cloud Firewalls
Make sure there's an inbound rule allowing TCP port 22 (or your custom SSH port). For security, scope it to your own IP rather than 0.0.0.0/0. Find your current IP with:
curl ifconfig.me
A packet dropped at the security-group level looks exactly like a timeout — this is the first thing to check on any cloud host.
Step 3: Check the OS firewall
If the cloud firewall is open, the server's own firewall might still be dropping you. From the server console:
sudo ufw status verbose
sudo iptables -L -n
Allow SSH if it's missing:
sudo ufw allow 22/tcp
The distinction matters: a firewall set to drop packets causes a timeout, while one set to reject causes "Connection refused." If you're timing out, look specifically for DROP rules.
Step 4: Is the server actually up?
A timeout can simply mean the machine is off, crashed, or overloaded. Check:
- The instance state in your provider's dashboard — running, not stopped
- A
ping, keeping in mind many servers block ICMP, so no reply isn't conclusive:
ping server.example.com
- The SSH port directly:
nc -vz -G 5 server.example.com 22
If nc also hangs and times out, it's a network or firewall problem — not SSH itself. If a fully booted server still times out, it may be out of memory or disk space — reboot it from the dashboard.
Step 5: Rule out your own network
Sometimes the problem is on your end:
- Corporate, school, or cafe Wi-Fi often blocks outbound port 22. Test from a phone hotspot — if it works there, the network is the blocker. The workaround is to also run SSH on port 443, or connect through a jump host.
- VPN — reaching a private server may require the VPN on; reaching a public one may break because of it. Toggle it and retry.
- Flaky local Wi-Fi — a long-standing Mac quirk has SSH timing out only on Wi-Fi. Try Ethernet, or restart your Wi-Fi.
Add keep-alives to your ~/.ssh/config so half-open connections fail fast instead of hanging:
Host *
ConnectTimeout 10
ServerAliveInterval 60
ServerAliveCountMax 3
Quick checklist
- The IP address is current — cloud IPs change on stop/start
- The cloud security group allows inbound TCP 22 from your IP
- The OS firewall has no
DROPrule blocking SSH - The server is actually running, with free memory and disk
- Your own network — Wi-Fi, VPN, corporate firewall — isn't blocking port 22
nc -vz host 22shows whether packets get through
Stop chasing timeouts
A timeout is almost always a firewall silently eating your packets — usually the cloud provider's security group, occasionally your own network.
Pluto Door keeps each connection's IP, port, and jump host stored together and applies sane timeouts and keep-alives by default, so a misconfigured server fails fast with a clear reason instead of hanging for 30 seconds. When you're juggling boxes across AWS, Hetzner, and a homelab, that adds up.
Work the checklist from the outside in — IP, cloud firewall, OS firewall, server, your own network — and you'll find exactly where the packets are dying.
