Windows Version
10.0.26100.8246
WSL Version
2.7.3.0
Are you using WSL 1 or WSL 2?
Kernel Version
6.6.114.1-1
Distro Version
Ubuntu 24.04 LTS (Noble)
Other Software
- curl 8.5.0 (x86_64-pc-linux-gnu) — used to reproduce the issue
- No VPN client active during testing
- No Docker Desktop installed
- Issue reproduces with any application making sustained HTTPS connections from WSL (curl, Python requests, Rust/hyper-based CLI tools)
Repro Steps
- Ensure WSL2 is in NAT networking mode (the default)
- Confirm
net.ipv4.tcp_timestamps is enabled (default): sysctl net.ipv4.tcp_timestamps → 1
- Attempt to download any resource larger than ~50KB via a sustained TCP stream:
curl -o /dev/null -w "%{time_total}\n" --max-time 15 https://example.com/large-page
- Observe the download starts, transfers 40-80KB, then stalls until timeout
Expected Behavior
The download completes in under 1 second (as it does from Windows natively on the same machine at the same moment).
Actual Behavior
The download stalls after receiving ~47-80KB of data and eventually times out. The TCP connection is established and data begins flowing, but the stream hangs mid-transfer.
Key observations:
- Small responses (<10KB) complete fine
- The same endpoint accessed via
curl.exe (Windows networking stack) from within WSL completes instantly (~0.14s)
- The issue is deterministically caused by TCP timestamps — toggling the setting on/off immediately reproduces/resolves the issue:
# Timestamps ON → stalls
$ sudo sysctl -w net.ipv4.tcp_timestamps=1
$ curl -o /dev/null -w "%{time_total}\n" --max-time 15 https://releases.ubuntu.com/noble/SHA256SUMS
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
20 229k 20 47632 0 0 3174 0 0:01:14 0:00:15 0:00:59 0
curl: (28) Operation timed out after 15002 milliseconds with 47632 out of 235038 bytes received
# Timestamps OFF → instant
$ sudo sysctl -w net.ipv4.tcp_timestamps=0
$ curl -o /dev/null -w "%{time_total}\n" --max-time 15 https://releases.ubuntu.com/noble/SHA256SUMS
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 229k 100 229k 0 0 2563k 0 --:--:-- --:--:-- --:--:-- 2578k
0.089521
This is 100% reproducible — toggling back and forth immediately changes behavior. Tested dozens of times across multiple wsl --shutdown cycles.
Additional Context
- Mirrored networking mode is unavailable on this system because IPv6 is disabled via registry (
DisabledComponents=0xff), which is common in enterprise environments.
- The issue appears to have been introduced by the April 2026 cumulative updates (KB5088467 / KB5083769 / KB5082420, installed April 22-24). Prior to these updates, WSL2 NAT mode worked without issue for months with TCP timestamps at the default (enabled).
- The issue is worse under network load — during low-traffic periods (early morning), the stall sometimes doesn't occur. During peak hours (afternoon/evening), it is 100% reproducible. This suggests the Hyper-V virtual switch's NAT connection tracking has a race condition or resource contention issue when processing TCP timestamp options.
- MSS clamping (
iptables -t mangle ... --set-mss 1360) partially mitigated the issue during low-load periods but did not resolve it during peak hours. Only disabling timestamps fully resolves it.
- Disabling Large Send Offload (LSO) on the vEthernet (WSL) adapter did not help and actually made connectivity worse.
Workaround
sudo sysctl -w net.ipv4.tcp_timestamps=0
Made persistent via /etc/wsl.conf:
[boot]
command=sysctl -w net.ipv4.tcp_timestamps=0
systemd=true
Root Cause Hypothesis
The Hyper-V virtual switch's NAT implementation appears to mishandle TCP timestamp options (RFC 7323) in packet headers during sustained transfers. When the NAT rewrites packets, it may be corrupting or incorrectly tracking timestamp values, causing the remote server's TCP stack to interpret the timestamps as invalid and stop sending data (or causing the NAT itself to drop packets with "unexpected" timestamp values).
This would explain:
- Why small transfers work (few packets, timestamps don't diverge)
- Why it's worse under load (more connections = more timestamp state to track = higher chance of collision/corruption)
- Why
curl.exe from WSL works (bypasses the virtual switch entirely, uses Windows TCP stack)
- Why disabling timestamps completely eliminates the issue (no timestamp options in packets = nothing for the NAT to mishandle)
Diagnostic Logs
No response
Windows Version
10.0.26100.8246
WSL Version
2.7.3.0
Are you using WSL 1 or WSL 2?
Kernel Version
6.6.114.1-1
Distro Version
Ubuntu 24.04 LTS (Noble)
Other Software
Repro Steps
net.ipv4.tcp_timestampsis enabled (default):sysctl net.ipv4.tcp_timestamps→ 1curl -o /dev/null -w "%{time_total}\n" --max-time 15 https://example.com/large-pageExpected Behavior
The download completes in under 1 second (as it does from Windows natively on the same machine at the same moment).
Actual Behavior
The download stalls after receiving ~47-80KB of data and eventually times out. The TCP connection is established and data begins flowing, but the stream hangs mid-transfer.
Key observations:
curl.exe(Windows networking stack) from within WSL completes instantly (~0.14s)This is 100% reproducible — toggling back and forth immediately changes behavior. Tested dozens of times across multiple
wsl --shutdowncycles.Additional Context
DisabledComponents=0xff), which is common in enterprise environments.iptables -t mangle ... --set-mss 1360) partially mitigated the issue during low-load periods but did not resolve it during peak hours. Only disabling timestamps fully resolves it.Workaround
Made persistent via
/etc/wsl.conf:Root Cause Hypothesis
The Hyper-V virtual switch's NAT implementation appears to mishandle TCP timestamp options (RFC 7323) in packet headers during sustained transfers. When the NAT rewrites packets, it may be corrupting or incorrectly tracking timestamp values, causing the remote server's TCP stack to interpret the timestamps as invalid and stop sending data (or causing the NAT itself to drop packets with "unexpected" timestamp values).
This would explain:
curl.exefrom WSL works (bypasses the virtual switch entirely, uses Windows TCP stack)Diagnostic Logs
No response