EC2 SSH Connection Timeout: Which Security Group Rules to Check

An EC2 SSH connection timeout is one of the most common blockers when launching a new instance — the fix is almost always a missing or misconfigured inbound rule in your Security Group.

TL;DR — Diagnostic Steps at a Glance

StepWhat to CheckCommon Fix
1Security Group inbound rulesAdd SSH (TCP 22) from your IP
2Subnet route tableEnsure 0.0.0.0/0 routes to an Internet Gateway
3Network ACL rulesAllow inbound TCP 22 and ephemeral return ports
4Instance public IP / Elastic IPConfirm a public IP is assigned
5Key pair and SSH usernameUse correct private key and AMI-specific username

Why SSH Times Out Instead of Refusing

A connection refused error means the TCP handshake reached the host but nothing is listening. A connection timed out error means packets never arrived — or replies never returned. On EC2, that silence is almost always a network-layer block, not an OS-level problem. The Security Group (an instance-level stateful firewall) is the first and most frequent culprit.

Analogy: Think of a Security Group as a bouncer at the door of your instance. If SSH (port 22) isn't on the guest list, your packets queue outside indefinitely — no rejection notice, just silence.

Step 1 — Fix the Security Group Inbound Rule

Security Groups use an implicit deny model: all inbound traffic is blocked unless an explicit allow rule exists. For SSH to work, you need a rule that permits inbound TCP on port 22 from your source IP.

Minimum required inbound rule:

  • Type: SSH
  • Protocol: TCP
  • Port range: 22
  • Source: Your public IP address (e.g., 203.0.113.10/32)

Using 0.0.0.0/0 as the source works but exposes port 22 to the entire internet. For production instances, restrict to your known IP or a bastion host's Security Group ID.

🔽 AWS CLI — Add SSH inbound rule to a Security Group
aws ec2 authorize-security-group-ingress \
  --group-id sg-0123456789abcdef0 \
  --protocol tcp \
  --port 22 \
  --cidr 203.0.113.10/32 \
  --region us-east-1

After adding the rule, Security Groups apply changes immediately — no instance reboot required.

Step 2 — Verify the Subnet Route Table

Even with a correct inbound rule, SSH will time out if the subnet has no path to the internet. Public subnets require a route that sends 0.0.0.0/0 traffic to an Internet Gateway (IGW).

Check your route table in the VPC console: navigate to VPC → Route Tables → Routes for the subnet hosting your instance. You should see a route like:

  • Destination: 0.0.0.0/0
  • Target: igw-xxxxxxxxxxxxxxxxx

If the target is a NAT Gateway or shows local only, the instance is in a private subnet. You cannot SSH directly into a private subnet instance from the internet — you need a bastion host or AWS Systems Manager Session Manager.

Step 3 — Check Network ACLs

Network ACLs (stateless subnet-level firewalls) are evaluated before traffic reaches the instance. Unlike Security Groups, ACLs are stateless — you must explicitly allow both the inbound request and the outbound reply.

Required ACL rules for SSH:

  • Inbound: Allow TCP port 22 from your source IP
  • Outbound: Allow TCP on the ephemeral port range (the exact range depends on the client OS — check the AWS VPC documentation for current guidance) back to your source IP

Default VPCs ship with a default Network ACL that allows all traffic. Custom ACLs start with a deny-all rule — a common source of confusion when teams migrate to custom VPCs.

Step 4 — Confirm a Public IP Is Assigned

An instance in a public subnet with a correct route table still won't be reachable if it has no public IP. Check the instance details in the EC2 console under Public IPv4 address.

If the field is empty, either:

  • Auto-assign public IP was disabled at launch (subnet default or explicit setting)
  • No Elastic IP has been associated

You cannot add a public IP to a running instance after launch without using an Elastic IP. Allocate an Elastic IP and associate it with the instance from the EC2 console or CLI.

Step 5 — Key Pair and SSH Username

Once network access is confirmed, a mismatch between the private key or the SSH username will produce an authentication error — but only after the TCP connection succeeds. If you're still timing out, this step isn't the cause. If you've resolved the timeout but now see a permission denied error, check these:

  • Private key file: Must be the .pem file corresponding to the key pair selected at launch. Permissions must be chmod 400.
  • SSH username: Varies by AMI. Common defaults for official AMIs include:
    • Amazon Linux 2 / Amazon Linux 2023: ec2-user
    • Ubuntu: ubuntu
    • RHEL: ec2-user or root (check AMI description)
    • SUSE: ec2-user
    • Debian: varies by AMI — check the AMI description or provider documentation. Not all Debian images use the same default username.

Only a subset of official AWS AMIs have standardized, well-documented default usernames. For marketplace or community AMIs — including many Debian images — the username is set by the AMI publisher and must be verified in the AMI's description or the publisher's documentation before connecting.

Full Diagnostic Flow

graph LR A[SSH Attempt] --> B{Public IP assigned?} B -- No --> C[Assign Elastic IP] B -- Yes --> D{IGW route exists?} D -- No --> E[Private subnet - use Bastion or SSM] D -- Yes --> F{Network ACL allows port 22?} F -- No --> G[Add ACL inbound and outbound rules] F -- Yes --> H{SG allows TCP 22 from your IP?} H -- No --> I[Add SG inbound rule] H -- Yes --> J[TCP Connected - Auth begins]
  1. Start: SSH attempt from your local machine.
  2. Public IP check: If no public IP exists, the packet has nowhere to go — assign an Elastic IP.
  3. Route Table check: If no IGW route exists, the subnet is private — use a bastion or Session Manager.
  4. Network ACL check: If the ACL blocks port 22 or ephemeral return ports, add explicit allow rules.
  5. Security Group check: If no inbound rule allows TCP 22 from your IP, add one — this is the most common fix.
  6. Connection established: TCP handshake succeeds; SSH authentication begins.

Production Gotcha — Your IP Changes, the Rule Doesn't

A common pitfall on dynamic home or office connections: you add an SSH rule scoped to your-ip/32, it works, then the next day you get a timeout again. Your ISP rotated your public IP — the Security Group rule still points to the old one. Teams sometimes respond by widening the source to 0.0.0.0/0 permanently, which trades the inconvenience for a real attack surface.

The correct approach: use AWS Systems Manager Session Manager for interactive shell access without opening port 22 at all, or maintain a dedicated bastion host with an Elastic IP whose Security Group you reference as the SSH source.

Common Mistake — Editing the Wrong Security Group

EC2 instances can have multiple Security Groups attached. Teams often add the SSH rule to one group and verify it looks correct — but the instance is actually using a different group that still has no port 22 rule. Before concluding a rule is missing, confirm which Security Groups are attached to the specific instance under EC2 → Instance → Security tab, then verify the inbound rules on each attached group.

Tradeoff — Restricting SSH vs. Operational Convenience

Locking SSH to a single /32 IP is secure but operationally brittle for teams with dynamic IPs or multiple engineers. The architectural tradeoff worth knowing: AWS Systems Manager Session Manager provides browser-based and CLI shell access using IAM authentication, with no inbound Security Group rule required and full session logging to CloudTrail and S3. For new deployments, this eliminates the SSH key management and port exposure problem entirely — at the cost of requiring the SSM Agent to be running and an appropriate IAM instance profile attached.

Wrap-Up

Most EC2 SSH timeouts resolve at Step 1 — a missing TCP 22 inbound rule in the Security Group. Work through the five steps in order: Security Group → Route Table → Network ACL → Public IP → Key/Username. For long-term security, consider replacing direct SSH with Session Manager to eliminate port 22 exposure entirely.

Glossary

TermDefinition
Security GroupA stateful, instance-level virtual firewall that controls inbound and outbound traffic. Implicit deny on all inbound traffic unless explicitly allowed.
Network ACLA stateless, subnet-level firewall evaluated before Security Groups. Requires explicit allow rules for both request and reply directions.
Internet Gateway (IGW)A horizontally scaled VPC component that enables communication between instances in a VPC and the internet.
Elastic IPA static public IPv4 address that can be allocated to your AWS account and associated with an EC2 instance.
Session ManagerAn AWS Systems Manager capability that provides secure, auditable shell access to EC2 instances without requiring open inbound ports or SSH keys.

Related Posts

Comments

Popular posts from this blog

EC2 No Internet Access in Custom VPC: Fix Internet Gateway and Route Table

Difference Between IAM User and IAM Role: Which One Should Your EC2 Use?