Skip to content

EC2 SSH connection timed out: the five causes in order of likelihood

An EC2 SSH connection timed out error means your packets are being dropped before they reach sshd. Here are the five causes ranked by likelihood, and how to test each one in minutes.

ssh: connect to host ... port 22: Operation timed out means your packets never got an answer — they were silently dropped somewhere between your laptop and the instance. That is a different failure from Connection refused (the instance answered and nothing is listening) or Permission denied (sshd answered and rejected your key). A timeout is almost always a network path problem, and on EC2 the path has exactly five places it breaks. In order of likelihood: the security group, a missing public IP or route, a network ACL, the OS firewall on the instance, and an outbound block on your side.

What’s happening

SSH to an EC2 instance crosses several filters in sequence: your local network’s egress rules, the internet, the VPC’s route table and internet gateway, the subnet’s network ACL, the instance’s security group, and finally the OS firewall (iptables, nftables, ufw, firewalld) before reaching sshd. Security groups and NACLs do not send TCP resets when they block traffic — they drop the packet and say nothing, which is exactly what a client experiences as a timeout.

The likelihood ranking comes from how these layers behave by default. Security groups deny everything inbound unless a rule allows it, and the allowed source is usually a specific IP — so the single most common trigger is that your public IP changed (new office, VPN toggled, ISP reassignment) and the old /32 rule no longer matches. Missing public IPs are next: instances launched into a private subnet, or into a subnet with auto-assign public IP disabled, have no route back to you at all. NACLs are less common because the default NACL allows everything, but someone tightening them and forgetting the ephemeral return ports breaks SSH in a way that confuses people for hours. OS firewalls and corporate egress blocks round out the list.

What to check first

  • Is the instance actually running with both status checks passed? A stopped or impaired instance times out too. EC2 > Instances > Status checks.
  • What is your current public IP, and does the security group allow it? Check https://checkip.amazonaws.com and compare against the inbound rule for port 22.
  • Does the instance have a public IPv4 (or are you expecting to reach a private IP over VPN/peering)? No public IP and no private path means no connection, full stop.
  • Are you using the right address? After a stop/start, a non-Elastic public IP changes. Connecting to yesterday’s IP times out against someone else’s instance or nothing at all.
  • Does EC2 Instance Connect work from the console? If the browser-based connection works, the instance and sshd are fine and the problem is on the network path between you and AWS.

How to verify

Confirm what you are dialing and what AWS thinks the instance has:

# Public IP, state, subnet, and security groups of the instance
aws ec2 describe-instances --instance-ids i-0123456789abcdef0 \
  --query 'Reservations[].Instances[].[State.Name,PublicIpAddress,PrivateIpAddress,SubnetId,SecurityGroups]' \
  --output json

# What does the security group actually allow inbound on 22?
aws ec2 describe-security-group-rules \
  --filters Name=group-id,Values=sg-0123456789abcdef0 \
  --query 'SecurityGroupRules[?IsEgress==`false`]'

Check the subnet’s route table for an internet gateway route, and the NACL:

# Route table for the subnet — look for 0.0.0.0/0 -> igw-...
aws ec2 describe-route-tables \
  --filters Name=association.subnet-id,Values=subnet-0123456789abcdef0 \
  --query 'RouteTables[].Routes'

# NACL entries for the subnet
aws ec2 describe-network-acls \
  --filters Name=association.subnet-id,Values=subnet-0123456789abcdef0 \
  --query 'NetworkAcls[].Entries'

If you want AWS to trace the whole path for you, VPC Reachability Analyzer (VPC > Reachability Analyzer) takes your source, the instance, and port 22, and tells you exactly which hop blocks it. It costs a small per-analysis fee but ends the guessing. The full connectivity checklist lives in the EC2 documentation at https://docs.aws.amazon.com/ec2/.

The fix

  1. Security group does not allow your current IP — the most common cause by a wide margin. Add or update the inbound rule: port 22, source = your current public IP as a /32. Do not “fix” it with 0.0.0.0/0 — that turns the timeout into a brute-force target. If your team’s IPs churn, front SSH with AWS Systems Manager Session Manager or EC2 Instance Connect Endpoint instead of widening the rule.
  2. No public IP, or no route to an internet gateway — if PublicIpAddress is empty, either associate an Elastic IP, or accept that this is a private instance and reach it the intended way: Session Manager, a bastion, VPN, or an EC2 Instance Connect Endpoint. If the subnet’s route table has no 0.0.0.0/0 -> igw- route, it is a private subnet and a public IP alone will not help.
  3. Network ACL blocking the connection or the return path — NACLs are stateless, so they need inbound port 22 and outbound ephemeral ports 1024-65535 allowed. If someone customized the NACL, check both directions. Details on the stateful/stateless split are in security groups vs NACLs.
  4. OS firewall on the instance — ufw, firewalld, or raw iptables rules can drop port 22 even when every AWS layer allows it. Use the EC2 serial console or Session Manager to get in without SSH and check sudo iptables -L -n or sudo ufw status.
  5. Your side is blocking outbound 22 — hotel and corporate networks commonly block outbound SSH. Test from a phone hotspot or another network. If that connects, the instance was never the problem.

When this is the wrong move

If Connection refused or Permission denied is the actual error, stop — this article’s checklist will waste your time, because packets are already reaching the instance. Refused means sshd is down or on another port; permission denied means keys or usernames. And if you find yourself opening port 22 to the world just to make a timeout go away, the better move is removing public SSH entirely: Session Manager gives shell access with IAM auth, auditing, and zero inbound rules.

Common mistakes

  • Opening 0.0.0.0/0 on port 22 “temporarily” and leaving it — every scanner on the internet finds it within minutes.
  • Chasing the instance for an hour when the real change was your own IP address after a VPN or network switch.
  • Editing the wrong security group — instances can have several attached, and the rule you added may sit on a group the instance does not use.
  • Forgetting that stop/start changes a non-Elastic public IP, then debugging a timeout against the old address.

Prevention

  • Replace public SSH with Session Manager or an EC2 Instance Connect Endpoint — no inbound rules, no IP allowlists to maintain.
  • If you must keep port 22 open, restrict it to a stable corporate range or VPN egress IP, and document it.
  • Use Elastic IPs (or DNS names) for anything you connect to by address, so stop/start does not silently move the target.
  • Leave the default NACL alone unless you have a concrete requirement; enforce policy in security groups where state tracking works for you.
  • Alarm on StatusCheckFailed so an impaired instance does not masquerade as a network problem.

Most SSH timeouts are a five-minute fix once you test the layers in order instead of at random. If nobody on your team truly owns the AWS environment end to end, that is the root of most of these problems — Stack Harbor runs AWS accounts daily under AWS Operations, and you can book an AWS review.