How a TCP Connection Closes

Run a Speed Test

Opening a TCP connection is a tidy three-step handshake. Closing one is a little more involved — a four-way exchange of FIN and ACK segments, plus a deliberate waiting period at the end called TIME_WAIT. The asymmetry is not an accident: it is what lets each side finish sending on its own schedule and guarantees no stray packet corrupts the next connection.

Closing Is Not Just the Handshake in Reverse

A TCP connection is full-duplex: data flows independently in both directions at once. That single fact shapes everything about how connections close. When one side has finished sending, the other side may still have plenty to say. So TCP does not slam the whole connection shut — it closes each direction separately. The side that is done sends a FIN ("I am finished sending"), but the conversation in the other direction can continue until that side, too, decides it is done.

If you have read about the three-way handshake, the contrast is instructive. Opening combines the server's acknowledgement and its own SYN into one segment, giving three steps. Closing keeps the two ends' shutdowns separate, giving four.

The Four-Way FIN Exchange

Call the side that initiates the close the active closer and the other the passive closer. A normal, graceful shutdown looks like this:

  1. FIN → The active closer sends a segment with the FIN flag set: "I have no more data to send."
  2. ACK ← The passive closer acknowledges that FIN. At this point the connection is half-closed — the active closer will send no more data, but the passive side can still send, and the active side keeps receiving.
  3. FIN ← When the passive closer has finished sending whatever it had left, it sends its own FIN.
  4. ACK → The active closer acknowledges that final FIN. The connection is now fully closed.

Like the SYN flag at the start, each FIN consumes one sequence number, so it is acknowledged with the next-expected value. Steps 2 and 3 are sometimes combined into a single FIN-ACK segment when the passive side has nothing more to send, collapsing the exchange to three messages — but the general, fully-described case is four.

StepDirectionFlagState after
1Active → PassiveFINActive enters FIN-WAIT
2Passive → ActiveACKPassive enters CLOSE-WAIT (half-closed)
3Passive → ActiveFINPassive enters LAST-ACK
4Active → PassiveACKActive enters TIME-WAIT, then CLOSED

Half-Close: One Direction at a Time

The window between steps 1 and 3 — the half-closed state — is a genuine and useful feature, not a quirk. An application can signal "I am done sending" while remaining ready to receive a response. A classic example is a client that sends a complete request, half-closes its sending direction to mark the end of input, and then waits to read the full reply before the server closes its side. Because each direction has its own FIN, TCP supports this cleanly.

Why TIME_WAIT Exists

After the active closer sends its final ACK (step 4), it does not immediately forget the connection. It enters TIME_WAIT and lingers there for roughly twice the maximum segment lifetime (the longest a packet is assumed to survive on the network) before fully releasing the resources. This pause does two important jobs:

  • It absorbs stray packets. If that final ACK is lost, the passive side will retransmit its FIN. The active closer must still be around to re-acknowledge it; otherwise the passive side never learns the connection closed cleanly.
  • It protects the next connection. A delayed or duplicated segment from the old connection could otherwise arrive after a new connection reuses the same socket 5-tuple and be mistaken for valid data. TIME_WAIT holds the old identifier out of service long enough for such ghosts to expire.

This is why a busy server shows many connections in TIME_WAIT — it is the stack being careful, not a resource leak. The only real downside appears at extreme connection rates, where a flood of TIME_WAIT sockets can tie up the supply of ephemeral ports; long-lived connections and connection reuse (keep-alive) avoid that by closing far less often.

FIN vs RST: Graceful Close vs Abrupt Abort

Not every connection ends politely. Alongside the FIN there is the RST (reset) flag, and the difference matters:

FINRST
Meaning"I have finished sending.""Tear this down now."
In-flight dataDelivered — everything sent so far is validDiscarded immediately
Acknowledged?Yes, part of an orderly exchangeNo — it is a one-shot abort
Typical causeNormal end of a conversationError: a packet for a dead connection, a refused port, an app crash

An RST is what a host sends when a packet arrives for a connection it has no record of, or when a client connects to a port with nothing listening — the fast, explicit "connection refused." Where a FIN is the graceful goodbye, an RST is hanging up mid-sentence.

Seeing It Yourself

The same tools that reveal the handshake show the teardown. In a packet capture, filter for the FIN or RST flags and you will see the closing exchange at the end of each TCP conversation. On a live host, ss or netstat will list sockets sitting in TIME_WAIT, CLOSE_WAIT, and FIN_WAIT — each one a connection partway through the sequence above. A large, stable count of CLOSE_WAIT sockets, unlike TIME_WAIT, often does signal a real bug: an application that received a FIN but never got around to closing its own side.

Frequently Asked Questions

How does a TCP connection close?

With a four-way exchange: one side sends a FIN, the other ACKs it, then sends its own FIN, which the first side ACKs. Each direction closes independently, so it takes four segments in the general case versus three to open.

Why is closing a four-way handshake?

Because TCP is full-duplex and each direction is shut down separately. The side receiving a FIN may still have data to send, so it acknowledges first and sends its own FIN only when finished — turning three potential steps into four.

What is the TIME_WAIT state?

The state the active closer enters after its final ACK. It waits about twice the maximum segment lifetime so delayed packets from the old connection drain away and cannot be mistaken for data on a new connection reusing the same address and port.

What is the difference between FIN and RST?

A FIN is a graceful close that preserves data sent so far; an RST is an abrupt abort that discards in-flight data and tears the connection down at once. FIN ends a normal conversation; RST signals something is wrong.

Why do I see so many TIME_WAIT connections on a server?

A server that closes many short-lived connections accumulates TIME_WAIT sockets, each lingering briefly. This is normal and protective. It only matters at very high connection rates, where it can exhaust ephemeral ports — mitigated by connection reuse.

Related Guides

More From This Section