Skip to main content
Your first session is free. Claim mine
PacketMentor logo
Open menu
Home
Training
CCNA Library (74)
Browse all CCNA topics →
Network (13)
Device Operations (5)
Network Access (12)
Wireless (6)
IP Connectivity (10)
IP Services (11)
Security (10)
Automation (7)
CCNP Library (15)
LabsPricing
Contact 📞 +1 (860) 556-3010 Book a Call
← All topics
Network Fundamentals Intermediate

TCP Connection States

What every TCP socket goes through from CLOSED to ESTABLISHED to TIME_WAIT. Covers each state, why TIME_WAIT exists (and frustrates web servers), and how `netstat`/`ss` shows you what's really happening.

TL;DR
  • TCP has 11 connection states. The interesting ones are LISTEN (server waiting), ESTABLISHED (data flowing), and TIME_WAIT (closed but recently).
  • TIME_WAIT is the 'wait 2 × MSL after closing' state — needed to handle stragglers. It's why busy web servers can run out of ports.
  • `netstat -an` (or `ss -an`) shows current state of every connection — invaluable troubleshooting.

Mental model

A TCP connection isn’t a binary “open or closed” thing — it’s a state machine with 11 distinct states. The OS kernel tracks the current state of every socket and moves it through the lifecycle based on packets sent/received.

You don’t need to memorize all 11. Five matter day-to-day:

StateWhat’s happening
LISTENServer is accepting connections on a port
SYN_SENTClient has sent SYN, waiting for SYN-ACK
SYN_RECEIVEDServer got the SYN, sent SYN-ACK, waiting for client’s ACK
ESTABLISHEDConnection is open, data flowing
TIME_WAITConnection closed; waiting before fully releasing the port

The full set (FIN_WAIT_1, FIN_WAIT_2, CLOSE_WAIT, LAST_ACK, CLOSING, CLOSED) handles the orderly teardown. Worth knowing they exist; not worth memorizing every transition for CCNA.

The states, in order of a typical connection

Server: CLOSED → LISTEN (listens on port 443)
Client: CLOSED → SYN_SENT (sends SYN)
Server: LISTEN → SYN_RECEIVED (responds SYN-ACK)
Client: SYN_SENT → ESTABLISHED (sends ACK, connection open)
Server: SYN_RECEIVED → ESTABLISHED (gets ACK, connection open)

... data flows ...

Client: ESTABLISHED → FIN_WAIT_1 (sends FIN)
Server: ESTABLISHED → CLOSE_WAIT (gets FIN, sends ACK)
Client: FIN_WAIT_1 → FIN_WAIT_2 (got server's ACK)
Server: CLOSE_WAIT → LAST_ACK (app calls close, sends FIN)
Client: FIN_WAIT_2 → TIME_WAIT (got server's FIN, sends ACK)
Server: LAST_ACK → CLOSED (got client's ACK)
Client: TIME_WAIT → CLOSED (after 2 × MSL timer expires)

TIME_WAIT — the one that confuses everyone

After a graceful close, the side that sent the first FIN enters TIME_WAIT and stays there for 2 × MSL (Maximum Segment Lifetime, typically 30-60 seconds on modern systems, so 60-120s total).

Why? Two reasons:

  1. Catch stragglers. If the final ACK is lost, the other side retransmits its FIN. The TIME_WAIT side responds with another ACK. Without TIME_WAIT, the second FIN reaches a “closed” socket and gets RST.

  2. Avoid stale connection confusion. Old packets from this connection might still be in flight. TIME_WAIT ensures they’re discarded before the same (src IP, src port, dst IP, dst port) 4-tuple can be reused for a new connection.

The annoying side-effect: a busy web server making lots of outbound connections (e.g. to backend services) accumulates lots of TIME_WAIT sockets on the source side, eating ephemeral ports.

$ netstat -an | grep TIME_WAIT | wc -l
12384

Mitigations:

  • HTTP keep-alive / connection pooling — reuse connections instead of opening new ones.
  • SO_REUSEADDR / SO_REUSEPORT — let new sockets bind even when there’s TIME_WAIT for the same 4-tuple.
  • Wider ephemeral port rangesysctl net.ipv4.ip_local_port_range on Linux.

Almost never the right fix: reducing TIME_WAIT duration. It’s there for a reason.

Looking at states in practice

Linux / macOS

$ ss -tan                       # modern (faster than netstat)
State          Recv-Q  Send-Q  Local Address:Port    Peer Address:Port
LISTEN         0       128             0.0.0.0:22              0.0.0.0:*
LISTEN         0       128             0.0.0.0:443             0.0.0.0:*
ESTABLISHED    0       0          192.168.1.5:55432       8.8.8.8:443
TIME_WAIT      0       0          192.168.1.5:55400       8.8.8.8:443
$ netstat -an                   # older but ubiquitous

Windows

> netstat -an

Cisco IOS

R1# show tcp brief
TCB         Local Address           Foreign Address        (state)
0xABCD123   10.0.0.1.22             10.0.0.50.55432        ESTAB
0xABCD124   10.0.0.1.22             0.0.0.0.0              LISTEN
SymptomState to investigate
Server keeps crashing under loadLots of TIME_WAIT → port exhaustion on client side
Client hangs foreverLikely SYN_SENT (server unreachable) or ESTABLISHED with nothing flowing
Server “not listening” on the expected portNo LISTEN entry — service not actually started
Connection refused (RST quickly)LISTEN absent, kernel rejects with RST
”Half-open” connections after firewall changesOne side is FIN_WAIT_*, other is CLOSE_WAIT — firewall dropped teardown packets

CLOSE_WAIT — the “your app forgot to close” smell

CLOSE_WAIT means: the remote side closed the connection (sent FIN), but your application hasn’t called close() yet. The socket sits there indefinitely.

$ ss -tan | grep CLOSE_WAIT
CLOSE_WAIT     1       0      192.168.1.5:80          10.0.0.42:55432
CLOSE_WAIT     1       0      192.168.1.5:80          10.0.0.42:55433
CLOSE_WAIT     1       0      192.168.1.5:80          10.0.0.42:55434

100 CLOSE_WAITs → likely an application bug. The app accepted connections but never properly closed them. Fix: trace the application’s connection lifecycle.

Common mistakes

  1. Lowering TIME_WAIT to “free ports.” Defeats the purpose. The right fix is connection reuse, not shortened TIME_WAIT.

  2. Confusing TIME_WAIT count with active connections. TIME_WAIT sockets aren’t doing anything — they’re memory-only. They look alarming but aren’t a problem unless you’re hitting port exhaustion.

  3. Restarting an app and finding the port “in use.” Likely TIME_WAIT for that port’s old connections. Wait 60-120s or use SO_REUSEADDR.

  4. Mistaking CLOSE_WAIT for normal. CLOSE_WAIT accumulation means application bug. Not network’s fault.

  5. Thinking SYN_SENT for a long time means slow server. It usually means the server is unreachable or filtered — packets aren’t getting through. Check connectivity and firewall.

  6. Using netstat -an on a busy server. Slow. Modern ss is much faster. ss -tan for TCP, ss -uan for UDP.

Lab to try tonight

  1. Open two terminals. In one: nc -l 8080 (Linux/macOS netcat listener).
  2. In the other: ss -tan | grep 8080. See the LISTEN state.
  3. From the second terminal: nc localhost 8080. Watch ss: now ESTABLISHED on both sides.
  4. In the first terminal (nc listener): press Ctrl+C to close. Watch ss again: state transitions to TIME_WAIT briefly, then disappears.
  5. Open Wireshark, filter tcp.port == 8080. Repeat the above. Match the packet exchange to state transitions.
  6. Bonus: start a Python http.server on port 80, run wrk or ab benchmark against it, watch your TIME_WAIT count climb on the client.

Cheat strip

StateMeaning
CLOSEDDefault. No connection.
LISTENServer waiting for clients
SYN_SENTClient has sent SYN, waiting for SYN-ACK
SYN_RECEIVEDServer got SYN, sent SYN-ACK, waiting for ACK
ESTABLISHEDOpen. Data flows.
FIN_WAIT_1We sent FIN, waiting for ACK
FIN_WAIT_2We got ACK, waiting for their FIN
TIME_WAITWe sent the final ACK, waiting 2 × MSL
CLOSE_WAITThey sent FIN — our app hasn’t called close() yet (bug!)
LAST_ACKWe sent FIN after CLOSE_WAIT, waiting for final ACK
CLOSINGBoth sides sent FIN simultaneously (rare)
ss -tanThe daily-driver command
Master this on a real network

Want this drilled into reflex?

1:1 weekly sessions, live feedback on your labs, and US interview prep — built around the CCNP® exam blueprint. Free first session. No card on file until you decide.

Claim my free session →

One topic per email, every fortnight

VLANs, OSPF, ACLs, subnetting, automation — written like this. Unsubscribe in one click.

We respect your inbox. One email per week, max. Unsubscribe any time.

Start typing — or browse popular topics below.

↑↓ navigate open Searches topics · labs · programs · pages