The SSH server terminated your connection unexpectedly, usually due to inactivity timeouts, network issues, or misconfigured keepalive settings. This can happen during idle sessions or when firewall rules drop inactive connections.
This error occurs when the SSH server closes your session without warning. It typically happens when the server times out an idle connection, the network becomes unstable, or server resources become constrained. Unlike a normal disconnect, the server doesn't send a graceful shutdown signal—it simply terminates the connection. The root cause is often a mismatch between client and server keepalive settings, where one side believes the connection is dead while the other is waiting for activity. Firewalls and NAT devices can also aggressively close idle TCP connections, and server configuration limits (like MaxStartups) can prevent new connections during high concurrency.
Add keepalive settings to your SSH client configuration to prevent the server from timing out idle connections.
Option A: Add to ~/.ssh/config (persistent)
Host *
ServerAliveInterval 60
ServerAliveCountMax 3Option B: Use command-line flag (one-time)
ssh -o ServerAliveInterval=60 user@hostThese settings tell your client to send a keepalive packet every 60 seconds and allow up to 3 unanswered packets before giving up (total ~180 seconds). Adjust the interval based on your timeout (use half your observed timeout value).
If you have access to the server, verify the sshd keepalive settings.
sudo nano /etc/ssh/sshd_configLook for or add these lines:
ClientAliveInterval 60
ClientAliveCountMax 3
TCPKeepAlive yesSave and restart sshd:
sudo systemctl restart sshd
# or on some systems:
sudo service sshd restartClientAliveInterval tells the server to send keepalive messages every 60 seconds. ClientAliveCountMax allows 3 unanswered messages before closing.
Incorrect file permissions can cause the server to reject your connection after initial authentication.
# On your LOCAL machine
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_rsa
chmod 644 ~/.ssh/id_rsa.pub
# On the SERVER
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keysCheck server logs for permission errors:
sudo tail -f /var/log/auth.log | grep sshdIf many clients are connecting simultaneously, the server may reject new connections.
sudo nano /etc/ssh/sshd_configFind the MaxStartups line (or add it if missing):
MaxStartups 10:30:100The format is start:rate:full. Default (10:30:100) means:
- Reject all connections once 100 unauthenticated connections exist
- Start rejecting at 10 connections with 30% probability increasing linearly
For high-concurrency scenarios, increase these values:
MaxStartups 100:30:500Restart sshd after changes:
sudo systemctl restart sshdEnable verbose output to see exactly where the connection closes.
Client-side diagnosis:
ssh -vvv user@hostThe output will show each step. Look for:
- debug1: Sending SSH2_MSG_CHANNEL_REQUEST followed by disconnect = likely server timeout
- Connection closed by remote host = server intentionally closed
- Broken pipe = network failure between client and server
Server-side diagnosis:
sudo tail -100 /var/log/auth.log | grep sshd
# or on macOS:
sudo log stream --predicate 'process == "sshd"'Look for messages like:
- Timeout, client not responding = keepalive timeout
- Connection reset by peer = network issue
- Authentication timeout = client took too long to authenticate
Rule out firewall and network issues.
Check if firewall is closing idle connections:
# Establish SSH connection, then let it idle for 10 minutes
# If it drops, your firewall likely has an idle timeout
# Test from a different network (mobile hotspot, different ISP) to isolate the issueMonitor connection with tcpdump (advanced):
sudo tcpdump -i any -n 'tcp and host <server_ip> and port 22' -vvIf you see no traffic during idle periods, the client isn't sending keepalives. If you see keepalives being sent but then an RST (reset) from the server/firewall, it's a timeout issue.
For corporate/public networks:
If behind a restrictive firewall, ask network admins about:
- TCP connection idle timeout
- Maximum concurrent connections limit
- SSH traffic filtering or inspection
You may need to use shorter keepalive intervals (30 seconds instead of 60).
Keepalive Negotiation: SSH has two keepalive mechanisms—TCP-level (TCPKeepAlive) which uses OS-level sockets, and application-level (ClientAliveInterval) which sends SSH protocol packets. Use both for maximum compatibility.
Firewall Timeout Windows: Most stateful firewalls timeout idle connections after 15-30 minutes. If your keepalive interval is longer than this, connections will still drop. Use ServerAliveInterval 60 and ServerAliveCountMax 1-3 as safe defaults, or decrease the interval if behind aggressive firewalls.
Rootless SSH and Systemd: On systems using rootless containers or systemd user services, SSH may not inherit keepalive settings properly. Test with verbose logging to confirm settings are applied.
Cloud Provider Defaults: AWS, GCP, and Azure have varying idle timeouts (typically 5-20 minutes for bastion hosts). Adjust keepalive accordingly when connecting to cloud instances.
Performance Considerations: While keepalive packets are minimal, very frequent intervals (5-10 seconds) can add overhead on high-latency links. Balance between preventing timeouts and minimizing traffic.
Long-Running Commands: For commands expected to take hours with no output, consider running them in a persistent terminal multiplexer (tmux/screen) or using nohup, as keepalive may not work during command output buffering.
Load key "/home/user/.ssh/id_rsa": invalid format
How to fix 'Load key invalid format' in SSH
Bad owner or permissions on /home/user/.ssh/config
How to fix "Bad owner or permissions on .ssh/config" in SSH
Error connecting to agent: Connection refused
How to fix "Error connecting to agent: Connection refused" in SSH
Connection closed by UNKNOWN port 65535
How to fix 'Connection closed by UNKNOWN port 65535' in SSH
Offending ECDSA key in /home/user/.ssh/known_hosts:line
How to fix "Offending ECDSA key in known_hosts" in SSH