TCP 2MSL & TIME_WAIT
What is 2MSL?#
MSL (Maximum Segment Lifetime) = the maximum time a TCP segment can exist in the network before being discarded. Typically 30s, so 2MSL = 60s.
After the active closer sends the final ACK, it enters TIME_WAIT and waits 2MSL before fully closing.
TIME_WAIT is on whoever initiates the close first (the active closer) — not specifically client or server.
Case 1: Client closes first → Client enters TIME_WAIT
Case 2: Server closes first → Server enters TIME_WAIT
Why 2MSL? Two Reasons#
Reason 1: Ensure the final ACK is delivered#
Active Closer Passive Closer
| |
|<──── FIN ──────────────────────────|
|──── ACK ──────────────────────────>| final ACK
| |
| ← enters TIME_WAIT (2MSL) |
What if the final ACK is lost?
|──── ACK ─────── X (lost) |
| | didn't receive ACK
|<──── FIN (retransmit) ────────────| retransmits FIN
|──── ACK ──────────────────────────>| re-ACK (still in TIME_WAIT)
Why exactly 2MSL?
Timeline:
t=0 Active closer sends ACK, enters TIME_WAIT
t≤1MSL ACK is either delivered or expires in network
t≤2MSL If lost, retransmitted FIN arrives within 1 more MSL
t=2MSL Safe — no retransmitted FIN means passive closer got the ACK
- Lost ACK travels at most 1 MSL
- Retransmitted FIN travels at most 1 MSL
- Worst case: 1 MSL + 1 MSL = 2MSL
Without TIME_WAIT: server retransmits FIN → OS has no socket → sends RST → server sees error instead of clean shutdown.
Reason 2: Let old duplicate segments die#
Connection 1: Client:5000 <──> Server:80 (closed at t=0)
Connection 2: Client:5000 <──> Server:80 (new, same 4-tuple)
WITHOUT TIME_WAIT:
t=0 Connection 1 closes
t=1 Connection 2 opens (same ports)
t=2 Delayed packet from Connection 1 arrives
Server accepts it as Connection 2 data → DATA CORRUPTION!
WITH TIME_WAIT:
t=0 Connection 1 closes, enters TIME_WAIT
t=1 Same ports? DENIED (still in TIME_WAIT)
t=60s TIME_WAIT expires, all old packets guaranteed dead
t=61s Connection 2 can now safely reuse the same ports
A segment sent at the last moment can live 1MSL. A response to it can live another 1MSL. After 2MSL, every in-flight segment from the old connection has expired.
Real-World: TIME_WAIT Accumulation#
High-traffic servers that actively close connections accumulate thousands of TIME_WAIT sockets:
$ ss -s
TCP: 32000 (estab 500, closed 28000, orphaned 0, timewait 27500)
# At 1000 connections/sec → up to 60,000 TIME_WAIT sockets
Mitigations#
| Approach | Sysctl | Trade-off |
|---|---|---|
| Reuse TIME_WAIT sockets | net.ipv4.tcp_tw_reuse=1 |
Safe — uses TCP timestamps to reject old segments |
| Reduce wait time | Lower net.ipv4.tcp_fin_timeout |
Risks stale packets |
| Let client close | Application design | Moves TIME_WAIT to client side, spread across many machines |
Troubleshooting#
# Count TIME_WAIT sockets
ss -s | grep timewait
# List TIME_WAIT connections
ss -tan state time-wait
# Check current settings
sysctl net.ipv4.tcp_tw_reuse
sysctl net.ipv4.tcp_fin_timeout
Reference#
Read other posts