In a TCP close, which side ends up in TIME-WAIT, what does that state protect against, and why does it last 2×MSL?
answer
- whoever says goodbye first
- the last ACK can be lost
- old segments must die out
- one lifetime each way
basics
~20 sThe side that sends the first FIN (the active closer) enters TIME-WAIT. It waits 2×MSL so it can re-acknowledge a retransmitted final FIN and so stray segments of this connection expire before the same four-tuple is reused.
solid answer
~50 sThe **active closer**, the side that sent the first `FIN`, goes `FIN-WAIT-1` → `FIN-WAIT-2` → `TIME-WAIT`; the passive side goes `CLOSE-WAIT` → `LAST-ACK` → `CLOSED`. `TIME-WAIT` does two jobs. First, the active closer sends the last segment of the exchange, the ACK of the peer's `FIN`, and cannot know it arrived; if it was lost the peer retransmits its `FIN`, and TIME-WAIT is there to acknowledge it again rather than answer with a reset. Second, it keeps the four-tuple out of use until delayed duplicates of this connection have expired, so none is accepted by a new incarnation. MSL, the maximum segment lifetime, bounds how long a segment can survive; waiting twice that covers a segment in flight in one direction plus a reply in the other. RFC 9293 takes MSL as 2 minutes, so 4 minutes; many implementations use less, which is their choice, not the RFC's.
go deeper
Remember that the side which closes first holds TIME-WAIT, that it lasts twice the maximum segment lifetime, and that it is normal, not an error.
Trace the close with every state on both sides, then give both jobs of TIME-WAIT: re-acknowledging a retransmitted FIN and letting old duplicates expire before the four-tuple returns.
Separate the RFC's 2-minute MSL from the shorter values implementations choose, and explain what shortening it, or aborting to skip it, puts at risk on busy hosts.
Treat TIME-WAIT as a deliberate cost of reliable teardown: decide which side of a system should carry it, and weigh reuse relaxations such as RFC 6191 against the safety they trade.
## The close sequence, state by state TCP closes each direction of a connection separately. The endpoint whose application closes first is the **active closer**; the other is the **passive closer**. RFC 9293, the current TCP specification, traces the normal close like this: 1. The active closer (A) sends `FIN` and enters `FIN-WAIT-1`. 2. The passive closer (B) acknowledges it and enters `CLOSE-WAIT`; on that ACK, A moves to `FIN-WAIT-2`. 3. B's application closes; B sends its own `FIN` and enters `LAST-ACK`. 4. A acknowledges B's `FIN` and enters `TIME-WAIT`. 5. B receives that ACK and goes to `CLOSED`. A stays in `TIME-WAIT` for 2×MSL, then goes to `CLOSED`. | Endpoint | States it passes through | Who ends it | |---|---|---| | Active closer | `FIN-WAIT-1`, `FIN-WAIT-2`, `TIME-WAIT` | a timer (2×MSL) | | Passive closer | `CLOSE-WAIT`, `LAST-ACK` | the arrival of the final ACK | If both applications close at the same moment, both `FIN`s cross on the wire, both sides pass through `CLOSING`, and **both** end in `TIME-WAIT` (RFC 9293, simultaneous close). The rule is "whoever sent a FIN before receiving one", not "the client" and not "the server". ## Job one: re-acknowledging the peer's FIN The last segment of a graceful close is A's ACK of B's `FIN`. Nothing acknowledges an ACK, so A can never learn whether it arrived. If it is lost, B, still in `LAST-ACK`, retransmits its `FIN`. - If A has kept the connection in `TIME-WAIT`, RFC 9293 tells it what to do: the only thing that should arrive is a retransmission of the remote FIN, so **acknowledge it and restart the 2 MSL timeout**. B gets its ACK and closes cleanly. - If A had already forgotten the connection, it would treat B's `FIN` as a segment for a connection that does not exist and answer with `RST`. B's application would see an error on a connection that actually closed correctly. The passive side needs no such state: it is waiting for an acknowledgment, and if one does not come it retransmits its `FIN` from `LAST-ACK`. ## Job two: letting the old incarnation die out A connection is identified by its **four-tuple**: local address, local port, remote address, remote port. Once it closes, a new connection with the same four-tuple, a new **incarnation**, can be opened. Segments of the old one may still be delayed somewhere in the network. If one arrives after the new incarnation starts and its sequence number happens to fall inside the new connection's window, it could be accepted as valid data. TCP's first defence is choosing initial sequence numbers so incarnations do not overlap (the handshake topic covers how). RFC 1337 explains why that is not enough on its own: for fast or long-lived connections, the clock-driven choice cannot prevent overlap, and **TIME-WAIT** is what removes that hazard, by keeping the four-tuple unusable until every old duplicate has had time to expire. ## Why two MSLs **MSL**, the Maximum Segment Lifetime, is the assumed longest time a TCP segment can survive in the network. RFC 9293 takes it to be **2 minutes**, calling this an engineering choice. The wait is twice that because the traffic that must drain runs both ways: - one MSL covers anything the active closer sent, including its final ACK, until it has either arrived or expired; - a second MSL covers the reply that final ACK could still trigger, such as a retransmitted `FIN` from the peer, together with any old segment travelling in the other direction. After 2×MSL no segment from either side of the old incarnation can still be alive. RFC 9293 makes the wait a requirement: when a connection is closed actively it **MUST** linger in `TIME-WAIT` for 2×MSL (MUST-13). ## RFC numbers versus implementation numbers | Value | Whose it is | |---|---| | MSL = 2 minutes, so TIME-WAIT = 4 minutes | RFC 9293 (the same figure RFC 793 used) | | TIME-WAIT of 60 seconds | an implementation choice; Linux, for example, uses it | | Reopening a four-tuple from TIME-WAIT when the new SYN's sequence number is higher | RFC 9293 MAY-2 | | Using TCP timestamps to accept such a SYN more often | RFC 6191, a Best Current Practice that RFC 9293 says SHOULD be implemented | Both RFC 9293 and RFC 6191 relax **when a new SYN may reuse the four-tuple**; neither changes who holds TIME-WAIT or why it exists. How applications and hosts reuse ports against it is a sockets topic. ## What TIME-WAIT is not - **Not a leak.** It is a timer on a closed connection and clears itself. - **Not the server's by definition.** It lands on whichever side closed first. - **Not a reservation of the port.** It reserves one four-tuple; a listening port keeps accepting other clients. - **Not a bug to be removed with RST.** An abort skips TIME-WAIT only by throwing away the protection it exists to give.
- What does a TCP endpoint in TIME-WAIT do if the peer's FIN arrives again?RFC 9293 says the only thing that should arrive in `TIME-WAIT` is a retransmission of the remote `FIN`: the endpoint acknowledges it again and restarts the 2 MSL timeout. That is exactly the case the state exists for, since the first ACK of that `FIN` was evidently lost.
- When both TCP endpoints close at the same moment, which one holds TIME-WAIT?Both. In a simultaneous close each side sends a `FIN` from `FIN-WAIT-1`, receives the peer's `FIN` before its own is acknowledged, moves to `CLOSING`, and on the ACK of its `FIN` enters `TIME-WAIT`. Each side was an active closer, so each waits 2×MSL.
- Why does the passive closer in TCP not need a TIME-WAIT of its own?Its last action is sending a `FIN`, which the peer must acknowledge. From `LAST-ACK` it retransmits that `FIN` until the ACK arrives, and then it knows the close completed. Only the side that sends the final, unacknowledged ACK is left uncertain.
saying these in an interview costs you the question
- The server always holds TIME-WAIT because it owns the listening port
- TIME-WAIT exists only because the stack is slow to free memory
- RFC 9293 fixes TIME-WAIT at 60 seconds
- TIME-WAIT lasts one MSL, just long enough for the last ACK to arrive
- The passive closer sits in TIME-WAIT waiting for the final ACK