Troubleshooting SSH Connection Timeout on WSL2 Ubuntu: Port 22 Keepalive Client Configuration
Resolve SSH connection timeouts from your WSL2 Ubuntu environment by configuring client-side keepalives and addressing common network and firewall issues.
Resolve SSH connection timeouts from your WSL2 Ubuntu environment by configuring client-side keepalives and addressing common network and firewall issues.
SSH connections from your Windows Subsystem for Linux 2 (WSL2) Ubuntu environment to remote servers can sometimes experience frustrating timeouts. This often manifests as a connection dropping after a period of inactivity, or even failing to establish entirely, disrupting critical development and deployment workflows. This guide will walk you through diagnosing and resolving these issues, focusing on client-side keepalive configurations and WSL2-specific networking challenges.
Symptom & Error Signature
Users typically encounter one of the following error messages in their WSL2 Ubuntu terminal when attempting to establish or maintain an SSH connection:
ssh user@remote_host
# ... connection hangs for a long time ...
Read from remote host remote_host: Connection timed out
ssh: connect to host remote_host port 22: Connection timed out
Or, if the connection was established but dropped due to inactivity:
# ... session was active, then suddenly unresponsive ...
packet_write_wait: Connection to x.x.x.x port 22: Broken pipe
Root Cause Analysis
The primary reasons for SSH connection timeouts when using WSL2 as a client often stem from a combination of default SSH client behavior and the unique networking characteristics of WSL2:
- Lack of Client-Side Keepalives: By default, the SSH client does not send periodic "keepalive" packets to the server. Intermediate network devices (like NAT routers, firewalls, or load balancers) are designed to drop idle connections to free up resources. Without keepalives, an SSH session might be considered idle and terminated by such devices, leading to a timeout or a "Broken pipe" error.
- WSL2 Networking Peculiarities:
- Hyper-V Virtual Switch & NAT: WSL2 leverages a Hyper-V virtual switch and often uses Network Address Translation (NAT) for network connectivity. This virtualized layer can sometimes introduce its own set of challenges, including aggressive connection timeout settings or transient network instability.
- Windows Defender Firewall: While less common for outbound SSH connections initiated from WSL2, the Windows Defender Firewall can, in certain configurations, interfere with network traffic or specific ports.
- Network State After Sleep/Hibernate: WSL2's network adapter can occasionally become unstable or misconfigured after the host Windows machine goes to sleep or hibernates, leading to connectivity issues upon waking.
- MTU (Maximum Transmission Unit) Mismatch: An MTU mismatch between your WSL2 environment, your local network, and the remote server's network path can cause packets to be silently dropped or fragmented inefficiently, leading to connection delays and eventual timeouts.
- DNS Resolution Issues: Slow or failing DNS lookups within WSL2 for the remote hostname can cause the
sshcommand to hang while attempting to resolve the IP address, eventually leading to a timeout error.
Step-by-Step Resolution
Follow these steps to diagnose and resolve SSH connection timeouts from your WSL2 Ubuntu instance.
1. Configure SSH Client Keepalives
The most common fix is to configure your SSH client to send periodic "alive" messages to the server. This prevents intermediate network devices from considering the connection idle and dropping it.
Create or Edit the SSH Client Configuration File: The SSH client configuration is typically located at
~/.ssh/configin your WSL2 Ubuntu environment. If the file or directory does not exist, create them.mkdir -p ~/.ssh chmod 700 ~/.ssh # Ensure correct permissions nano ~/.ssh/configAdd Keepalive Directives: Inside the
~/.ssh/configfile, add the following lines. You can apply them globally to all SSH connections or to specific hosts.Host * ServerAliveInterval 60 ServerAliveCountMax 5ServerAliveInterval 60: This tells the SSH client to send a null packet to the server every 60 seconds if no data has been exchanged. This keeps the connection "alive" in the eyes of network devices.ServerAliveCountMax 5: If the client does not receive any response from the server after sending 5 consecutive keepalive messages, it will disconnect. WithServerAliveInterval 60, this means the connection will be dropped after5 * 60 = 300seconds (5 minutes) of unresponsiveness.
For specific hosts, you can define blocks:
Host my_remote_server HostName your.remote.server.com User your_username ServerAliveInterval 60 ServerAliveCountMax 3 Host another_server HostName another.server.example.org User admin ServerAliveInterval 30 ServerAliveCountMax 5Ensure that the permissions for your
~/.sshdirectory are700(drwx------) and for~/.ssh/configare600(-rw-------). Incorrect permissions will cause SSH to ignore the configuration file due to security concerns.Test the Connection: Save the changes to
~/.ssh/configand try your SSH connection again.ssh user@remote_host
2. Verify WSL2 Network Connectivity and DNS Resolution
Ensure that your WSL2 instance has stable network connectivity and can resolve hostnames correctly.
Test Basic Connectivity: From your WSL2 terminal, try to ping the remote server's IP address and a public website.
ping -c 4 8.8.8.8 # Ping Google's DNS server ping -c 4 your.remote.server.com # Ping your SSH target by hostname ping -c 4 <remote_server_IP_address> # Ping your SSH target by IPIf
pingto8.8.8.8fails, your WSL2 network is down. If pinging the IP works but the hostname fails, you have a DNS issue.Check DNS Resolution: Verify that your WSL2 instance can resolve hostnames.
cat /etc/resolv.conf # Example output: # nameserver 172.X.X.X # This is often the WSL2-managed DNS server # nameserver 8.8.8.8 # Or directly assigned by Windows dig your.remote.server.comIf
digfails or is very slow, DNS resolution is a problem. You might temporarily add a public DNS server to/etc/resolv.conf(e.g.,nameserver 8.8.8.8) for testing, but be aware that WSL2 often overwrites this file. For persistent custom DNS, you need to configure~/.wslconfig(see section 7).
3. Adjust Windows Defender Firewall Rules
While typically not the cause for outbound client-initiated connections, Windows Defender Firewall can sometimes interfere.
Check Firewall Logs: Review your Windows Event Viewer (Applications and Services Logs -> Microsoft -> Windows -> Windows Firewall With Advanced Security -> Firewall) for any dropped packets originating from your WSL2 virtual network adapter to the remote SSH port (22).
Temporarily Disable Firewall (for testing only): As a diagnostic step, you can temporarily disable Windows Defender Firewall on the Public or Private profile (whichever your WSL2 virtual network uses, typically Private) to rule it out.
Disabling your firewall leaves your system vulnerable. Only do this in a controlled environment and re-enable it immediately after testing.
Create Outbound Rule: If the firewall is indeed blocking, create an outbound rule allowing TCP traffic on port 22 from any source to any destination. This is typically done via "Windows Defender Firewall with Advanced Security" in Windows.
4. Investigate MTU Settings
An MTU mismatch can cause packet fragmentation and silent drops, leading to timeouts.
Identify WSL2 Network Interface: Inside your WSL2 Ubuntu terminal, identify your primary network interface. It's usually
eth0.ip a | grep "inet "Look for the interface with an IP address (e.g.,
eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 ...). Note itsmtuvalue.Test MTU to Remote Host: Use
pingwith thedo(Don't Fragment) flag to test the maximum packet size that can reach your remote server without fragmentation. Start with your current MTU (e.g., 1500) and decrease it gradually. The actual data size forping -sisMTU - 28(for IP/ICMP headers).ping -c 4 -M do -s 1472 your.remote.server.com # For MTU 1500 # If this fails, try smaller: ping -c 4 -M do -s 1400 your.remote.server.com # Keep decreasing until it succeeds, then you've found your maximum payload.If
pingstarts succeeding at a smaller size (e.g.,1400), then your effective MTU is1400 + 28 = 1428.Adjust MTU (if necessary): If you determine a smaller MTU is required, you can temporarily set it in WSL2. However, this change is often reset after a WSL2 restart.
sudo ip link set dev eth0 mtu 1428 # Replace eth0 and 1428 with your valuesPermanently changing MTU in WSL2 is tricky as
netplanisn't typically used foreth0and changes often don't persist. If this is a persistent issue, consider checking the MTU settings on your Windows host network adapter or home router.
5. Reset WSL2 Network Adapters
Sometimes, WSL2's internal networking can get into a bad state. A full reset can resolve transient issues.
Shut Down WSL2 Instances: From an elevated PowerShell or Command Prompt on Windows:
wsl --shutdownRenew Windows IP Configuration: Still in PowerShell/CMD:
ipconfig /release ipconfig /renewRe-launch WSL2: Simply open your Ubuntu distribution from the Start Menu or by running
wslin PowerShell. This will reinitialize the WSL2 network adapter.
6. System-Wide TCP Keepalive Settings (Advanced)
These settings control the operating system's default TCP keepalive behavior. While ServerAliveInterval in SSH config is usually sufficient for client-side issues, adjusting system-wide TCP keepalives can sometimes help, especially if many applications are experiencing similar timeouts.
Check Current Settings:
sysctl -a | grep keepaliveYou'll see values like:
net.ipv4.tcp_keepalive_time: The time (in seconds) an idle TCP connection remains active before TCP starts sending keepalive probes. Default is often 7200 seconds (2 hours).net.ipv4.tcp_keepalive_intvl: The time (in seconds) between individual keepalive probes. Default is often 75 seconds.net.ipv4.tcp_keepalive_probes: The number of keepalive probes TCP sends before dropping the connection. Default is often 9.
Modify Settings (Temporarily): For testing, you can change them immediately:
sudo sysctl -w net.ipv4.tcp_keepalive_time=600 sudo sysctl -w net.ipv4.tcp_keepalive_intvl=60 sudo sysctl -w net.ipv4.tcp_keepalive_probes=20This sets idle timeout to 10 minutes, probes every minute, up to 20 times.
Make Changes Persistent: To make these changes permanent, edit
/etc/sysctl.conf.sudo nano /etc/sysctl.confAdd or modify the following lines:
# Custom TCP Keepalive Settings for WSL2 (optional) net.ipv4.tcp_keepalive_time = 600 net.ipv4.tcp_keepalive_intvl = 60 net.ipv4.tcp_keepalive_probes = 20Apply the changes:
sudo sysctl -pModifying system-wide TCP keepalive settings can affect all applications using TCP. Only do this if you understand the implications and SSH client-specific settings are not sufficient.
7. Troubleshoot DNS Resolution within WSL2
If you identified DNS issues in Step 2, here's how to address them more robustly.
Check
/etc/resolv.conf: WSL2 dynamically generates/etc/resolv.conf. By default, it points to a virtual DNS server provided by Windows.cat /etc/resolv.confDisable Auto-Generation and Set Custom DNS: If the auto-generated DNS server is unreliable, you can prevent WSL2 from overwriting
resolv.confand specify your own DNS servers.Create or edit the
.wslconfigfile in your Windows user profile directory (C:Users<YourUsername>.wslconfig). If it doesn't exist, create it.# .wslconfig [wsl2] dns=8.8.8.8 dns=8.8.4.4 generateResolvConf=falseReplace
8.8.8.8and8.8.4.4with your preferred reliable DNS servers (e.g., your router's IP, corporate DNS, or other public DNS).Shut down WSL2 for changes to take effect:
wsl --shutdownRe-launch your WSL2 instance. Your
/etc/resolv.confshould now reflect the custom DNS servers you specified.
By systematically applying these troubleshooting steps, you should be able to resolve persistent SSH connection timeouts when working from your WSL2 Ubuntu environment.
Our Production Verification Guarantee
Encountering a bug not covered here or running a non-standard kernel configuration? Our solutions are continually refined against real production incidents. Submit an environment trace for our editorial team to replicate.