Resolving SSH Connection Timeout on Port 22: Keepalive Intervals & ClientAlive Configuration
Troubleshoot common SSH connection timeouts on port 22. Learn to configure client and server keepalive intervals, resolve network issues, and secure your SSH daemon for stable access.
Troubleshoot common SSH connection timeouts on port 22. Learn to configure client and server keepalive intervals, resolve network issues, and secure your SSH daemon for stable access.
When managing remote servers, an SSH connection timeout can be a significant roadblock, disrupting your workflow and preventing critical administrative tasks. This guide dives deep into diagnosing and resolving the common "SSH connection timeout" error, particularly when dealing with port 22 and the crucial role of keepalive intervals, both on the client and server sides. We'll explore network factors, SSH daemon configurations, and system resource considerations to ensure your SSH sessions remain stable and reliable.
Symptom & Error Signature
Users typically experience one of the following messages on their terminal when an SSH connection times out:
$ ssh user@your_server_ip
# After a period of inactivity or sometimes immediately after connection
ssh: connect to host your_server_ip port 22: Connection timed out
Or, for existing sessions that suddenly disconnect:
Read from remote host your_server_ip: Connection reset by peer
packet_write_wait: Connection to your_server_ip port 22: Broken pipe
On the server side, a pure timeout might not leave specific error messages in auth.log or syslog unless the connection was partially established before dropping. However, excessive failed attempts or resource exhaustion might show up:
# Example from /var/log/auth.log or journalctl -u sshd
Oct 26 10:30:05 your_server_name sshd[12345]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=client_ip user=user
Oct 26 10:30:05 your_server_name sshd[12345]: Failed password for user from client_ip port 54321 ssh2
Root Cause Analysis
SSH connection timeouts stem from several underlying issues, often related to network stability, firewall rules, or SSH daemon configuration:
- Network Intermediaries Dropping Idle Connections: This is a very common cause. Firewalls (local or external), NAT devices, or load balancers along the connection path are often configured to drop TCP connections that remain idle for a certain period to conserve resources.
- Server-Side SSH Daemon (
sshd) Configuration:ClientAliveIntervalandClientAliveCountMax: These settings in/etc/ssh/sshd_configdetermine how often the server sends "keepalive" messages to the client and how many unacknowledged messages it tolerates before disconnecting. If these are too low or not configured, the server might prematurely close idle connections.LoginGraceTime: The maximum time in seconds for a user to authenticate. If exceeded, the connection is closed.MaxStartups: The maximum number of concurrent unauthenticated connection attempts allowed. If this limit is hit, new connections (including legitimate ones) may be dropped or time out.
- Client-Side SSH Configuration:
ServerAliveIntervalandServerAliveCountMax: Similar to the server-side settings, these client-side options in~/.ssh/configor/etc/ssh/ssh_configcontrol how often the client sends keepalive messages to the server. If the client doesn't send these, an intermediate network device or the server might deem the connection idle and terminate it.
- Server Resource Exhaustion: High CPU load, insufficient RAM, disk I/O bottlenecks, or an excessive number of active processes can make the
sshdprocess unresponsive, leading to timeouts. - DDoS or Brute-Force Attacks: A deluge of connection attempts can saturate the
sshdprocess, preventing legitimate connections from being established or maintained. - Incorrect Firewall Rules: Both server-side and client-side firewalls can inadvertently block SSH traffic or specific ports.
Step-by-Step Resolution
Follow these steps to diagnose and resolve SSH connection timeouts. It's recommended to start with the simplest checks and move to more complex configurations.
1. Verify Basic Network Connectivity & Firewall Status
Before diving into SSH-specific configurations, ensure there's fundamental network reachability to your server on port 22.
From your local machine:
$ ping your_server_ip $ traceroute your_server_ip # or tracert on Windows $ telnet your_server_ip 22If
pingfails, there's a fundamental network issue.traceroutecan help pinpoint where the connection is failing.telnetshould show anSSH-2.0-OpenSSH_...banner; if it hangs or gives "Connection refused", a firewall orsshdservice issue is likely.On the server (if you have console access or an alternative way to connect): Check the firewall status. For Ubuntu/Debian,
ufwis common.$ sudo ufw status verbose # Expected output should show '22/tcp ALLOW Anywhere' or similarIf you use
iptablesornftablesdirectly:$ sudo iptables -L -v -n | grep -i "ssh|22" $ sudo nft list ruleset # For nftablesEnsure that port 22 is explicitly allowed for incoming TCP connections. Also, check any cloud provider security groups (AWS Security Groups, Azure Network Security Groups, Google Cloud Firewall Rules) that might be blocking traffic.
2. Configure Client-Side SSH Keepalives
To prevent your client from being disconnected due to inactivity or intermediate network devices dropping idle connections, configure ServerAliveInterval and ServerAliveCountMax.
Edit or create
~/.ssh/configon your local machine:$ nano ~/.ssh/configAdd or modify the following lines. You can apply this globally for all hosts or for specific hosts:
Host * ServerAliveInterval 60 ServerAliveCountMax 3ServerAliveInterval 60tells the SSH client to send a null packet to the server every 60 seconds if no data has been exchanged.ServerAliveCountMax 3means the client will send up to 3 such messages without receiving any response from the server before it gives up and disconnects. With these settings, your SSH session will remain active even if idle, potentially keeping it alive for60 * 3 = 180seconds (3 minutes) before disconnecting if the server becomes completely unresponsive.For a single SSH command: You can specify these options directly:
$ ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=3 user@your_server_ip
3. Adjust Server-Side SSH Daemon Keepalives
If the client-side settings don't fully resolve the issue, the server itself might be configured to aggressively drop idle connections. You'll need to modify /etc/ssh/sshd_config on the server.
Connect to your server (via console or an existing stable SSH session) and edit
sshd_config:$ sudo nano /etc/ssh/sshd_configLocate and modify (or add) the following lines:
# How often the server sends a "keepalive" message to the client ClientAliveInterval 120 # How many times the server will send a keepalive without receiving a response ClientAliveCountMax 2 # Maximum time in seconds for authentication. Set to 0 to disable. LoginGraceTime 120sClientAliveInterval 120instructs thesshdserver to send a null packet to the client every 120 seconds if no data has been received from the client.ClientAliveCountMax 2specifies that if the server doesn't receive a response after sending 2 such messages, it will disconnect the client. This means the server will wait for120 * 2 = 240seconds (4 minutes) of unresponsiveness before disconnecting.LoginGraceTime 120sprovides 120 seconds for a user to complete authentication before the connection is closed.Restart the SSH service for changes to take effect:
$ sudo systemctl restart sshdAlways be extremely cautious when modifying
/etc/ssh/sshd_config. Incorrect syntax or invalid settings can lock you out of your server. It's highly recommended to keep a separate, active SSH session open while testing changes, or have console access available. After saving changes, test with a new SSH session before closing the old one.
4. Address Server Resource Constraints & SSH Saturation
If keepalives don't help, the server itself might be struggling.
Monitor server resources: Use
top,htop,free -h,df -hto check CPU, memory, and disk usage.$ top $ htop # If installed $ free -h $ df -hLook for consistently high CPU usage, low free memory (especially swap usage), or disk I/O bottlenecks.
Check
MaxStartupsinsshd_config: This setting limits the number of concurrent unauthenticated connections to the SSH daemon. If set too low, it can cause legitimate connection attempts to time out.$ sudo nano /etc/ssh/sshd_configFind or add
MaxStartups. The default is often10:30:100(meaning 10 unauthenticated connections, then 30% chance of dropping new connections until 100 connections, then all new connections are dropped). You might need to increase this if you have many users or services trying to connect concurrently, but be cautious as it can expose you to brute-force attacks.# MaxStartups 10:30:100Consider increasing
MaxStartupsif you suspect connection saturation, but it's often better to combine this withfail2ban.Implement
fail2banfor brute-force protection:fail2bandynamically blocks IPs that show malicious behavior, such as repeated failed SSH login attempts. This prevents yoursshdfrom being overwhelmed.$ sudo apt update $ sudo apt install fail2ban $ sudo systemctl enable fail2ban $ sudo systemctl start fail2banCreate a local configuration file to override defaults:
$ sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local $ sudo nano /etc/fail2ban/jail.localUnder the
[sshd]section, ensureenabled = true. You can also adjustbantimeandfindtime.[sshd] enabled = true port = ssh logpath = %(sshd_log)s backend = %(sshd_backend)s bantime = 1h # Ban for 1 hour findtime = 10m # Scan last 10 minutes maxretry = 5 # Ban after 5 failed attemptsReload
fail2banafter changes:$ sudo systemctl restart fail2banYou can check the status:
$ sudo fail2ban-client status sshd
5. Consider Mosh for Intermittent Connections (Alternative Solution)
If you frequently work over unreliable networks (e.g., Wi-Fi with signal drops, mobile data), Mosh (Mobile Shell) can be a superior alternative to SSH. Mosh maintains a continuous connection even with IP address changes and intermittent connectivity, providing a much smoother experience.
- Install Mosh on both your client and server:
$ sudo apt install mosh - Ensure UDP ports 60000-60010 are open on your server's firewall. Mosh uses UDP for its main connection.
$ sudo ufw allow 60000:60010/udp $ sudo ufw reload - Connect using Mosh:
Mosh will still use SSH for initial authentication, but then switches to its UDP protocol for the session.$ mosh user@your_server_ip
6. Review Docker & Container Networking (if applicable)
If you are trying to SSH into a Docker container, ensure the port mapping is correctly configured and the SSH server inside the container is running and accessible.
Check Docker port mapping: When starting your container, ensure you've mapped port 22 inside the container to a host port.
$ docker run -p 2222:22 -d your_image_nameThen, you would connect to
ssh user@your_host_ip -p 2222.Verify SSH service within the container: Ensure
sshdis actually running inside your Docker container. You might need to exec into the container to check:$ docker ps $ docker exec -it <container_id> bash $ service ssh status # or systemctl status sshd, or ps aux | grep sshd
By systematically working through these steps, you should be able to diagnose and resolve most SSH connection timeout issues, ensuring stable and reliable access to your servers.