Preventing lost and delayed packets affecting future connections is only a secondary purpose of TIME_WAIT
1. TCP is hardened against such packets by virtue of the receive window and, in modern implementations, timestamps.
Instead, TIME_WAIT
's primary purpose is to handle the case in which the final ACK
is lost. In such a case the final FIN
will be re-received and the final ACK
will need to be re-transmitted. This is necessary because there is no ACK
ing an ACK
, or the two endpoints would be ACK
ing each other forever. Instead, one side sends the final ACK
and waits for some time in TIME_WAIT
so as to be fairly certain that the other endpoint received said ACK
and did not re-transmit its FIN
.
However, the fact that the endpoint that passively closes does not enter a state equivalent to TIME_WAIT
I view as a design flaw in TCP. Have a look at the TCP state diagram in this page, and consider the case where the second last ACK
is lost:

Diagram Key:
Green: State | Blue: API calls | Red: errors, events and notes | Purple line: connection state save-points
The problem is that the two Endpoints get out of sync if the second-last ACK
is lost: Endpoint A believes a simultaneous close is happening and awaits a final ACK
, whereas Endpoint B believes that the connection is fully closed both ways (Diagram 1).
This eventually cleans itself up if the connection is left as-is (Diagram 2), but nothing stops Endpoint B from trying to re-open the connection (Diagram 3) which results in connection reset
errors (Diagrams 4 and 5).
A better design would have been to merge the CLOSING
and LAST_ACK
states so that both ends go through TIME_WAIT
, at the cost of slightly more memory usage at the passively closing end.
1No direct mention of TIME_WAIT
's secondary purpose of preventing segments from an old incarnation of the connection from interfering with a new incarnation is made in RFC 739, and can be only vaguely inferred from the sections on quiet time and section 4.2.2.13 of RFC 1122. I notice that RFC 6528 Section 2 from 2012 states:
It is interesting to note that, as a matter of fact, protection
against stale segments from a previous incarnation of the connection
is enforced by preventing the creation of a new incarnation of a
previous connection before 2*MSL have passed since a segment
corresponding to the old incarnation was last seen (where "MSL" is
the "Maximum Segment Lifetime" [RFC0793]). This is accomplished by
the TIME-WAIT state and TCP's "quiet time" concept
However I find this to be incorrect as a connection that is reset does not enter the TIME_WAIT
state and instead enters the CLOSED
or LISTEN
states. So old segments could still be in flight at a time when the connection could be re-opened. This could perhaps be remedied by having reset connections go into a TIME_WAIT
-like state. The confusion over this dual-purpose may be the root cause of these inconsistencies.