Inspecting Linux Sockets with ss (and Why netstat Is Lying to You)
ss replaces netstat with faster, richer socket inspection — accept queues, TCP internals, filters. Learn to drive it and use AI to turn socket state into a verdict.
- #linux
- #ai
- #networking
- #ss
- #sockets
- #troubleshooting
Someone reports “the service is up but won’t accept connections.” You SSH in, the process is running, the port is listening, and yet clients get refused or hang. The answer is almost always sitting in a place netstat either won’t show you or shows you slowly and wrong: the socket’s accept queue, its backlog, or the per-connection TCP internals. ss puts all of that one flag away — and on a busy box it returns in milliseconds where netstat chews through /proc and lags.
netstat is deprecated. Not “old but fine” — actually deprecated, part of the abandoned net-tools package, and missing capabilities ss has had for a decade. If ss still isn’t in your fingers, this is the article to fix that. Here’s how I drive it for real socket debugging, and where an AI copilot turns a socket dump into an answer.
Why ss beats netstat
ss (socket statistics) reads socket info directly from the kernel’s netlink interface instead of parsing /proc/net/* line by line. The practical consequences:
- Speed. On a host with tens of thousands of connections,
netstat -ancan take seconds;ss -anis near-instant. - TCP internals.
ssexposes per-socket congestion window, RTT, retransmits, and pacing —netstatsimply can’t. - Real filtering.
sshas a state-and-address filter language so you query precisely instead ofgrep-ing text. - Accurate queues. It shows accept-queue depth and configured backlog for listeners, which is the single most useful thing for “won’t accept connections.”
The commands I actually use
# Listening TCP sockets with the owning process and backlog
ss -tlnp
# All TCP, no name resolution (fast)
ss -tan
# A one-line summary of socket counts by state
ss -s
# Everything about connections to/from a host
ss -tan dst 10.0.0.5
# TCP internals: cwnd, rtt, retransmits — performance gold
ss -ti
The flags compose: t = TCP, u = UDP, l = listening, n = numeric (no DNS), p = process, a = all, i = TCP info, e = extended.
Reading a listener’s queue — the killer feature
This is the trick that solves “up but won’t accept.” For a LISTEN socket, ss overloads two columns with special meaning:
ss -tlnp '( sport = :8080 )'
# State Recv-Q Send-Q Local Address:Port
# LISTEN 129 128 0.0.0.0:8080
On a LISTEN socket:
- Recv-Q = the current number of connections waiting in the accept queue (i.e., fully established, waiting for the app to
accept()them). - Send-Q = the maximum backlog — the smaller of the app’s
listen()backlog andnet.core.somaxconn.
So Recv-Q 129, Send-Q 128 means the accept queue is full and overflowing — the app isn’t calling accept() fast enough (or is wedged), and new connections are getting dropped. That one line just diagnosed the entire incident. On an established socket those same columns mean unread/unacked bytes — completely different semantics, which is why people misread them.
Filtering like you mean it
ss’s filter language beats piping through grep:
# Only sockets in a specific state
ss -tan state established
ss -tan state time-wait | wc -l
ss -tan state syn-recv # possible SYN-flood or backlog overflow
# Combine state and address conditions
ss -tan state established '( dport = :443 or sport = :443 )'
# Sockets with a large send queue (backed-up writers)
ss -tan '( send-q > 0 )'
TCP internals for performance work
When throughput is the complaint, ss -ti exposes what’s actually happening on each connection:
ss -ti dst 203.0.113.10
# ... cwnd:10 ssthresh:7 ... rtt:84.3/2.1 retrans:0/3 ...
A cwnd pinned tiny with a healthy RTT and near-zero retransmits points at a buffer or application limit, not the network. Retransmits climbing points at loss. This is the per-socket evidence that keeps you from guessing.
Where AI turns the dump into a verdict
A socket investigation produces several captures — ss -s summary, the suspect-state list, the listener’s queue, maybe ss -ti — and the value is in correlating them into one diagnosis. That correlation is what I hand to an AI copilot.
Prompt: You are a senior Linux engineer. Symptom: clients intermittently get connection-refused to our app on :8080. Here is
ss -tlnp '( sport = :8080 )'(Recv-Q 129 / Send-Q 128),ss -s, anddmesg | grep -i listen. Tell me whether this is an app-side accept problem or a kernel backlog limit, the exact fix, and how to verify it’s resolved.Response (excerpt): Recv-Q (129) exceeding Send-Q (128) means the accept queue is full and overflowing — confirmed by the “TCP: … possible SYN flooding … Sending cookies” / ListenOverflows signal in dmesg. This is primarily an application problem: the app isn’t
accept()-ing fast enough (blocked worker, undersized thread pool). Raisingnet.core.somaxconnAND the app’slisten()backlog only helps if the app then drains the queue — if workers are stuck, a bigger queue just delays the drops. Fix order: (1) find why the app stalls (ss -tan state syn-recv | wc -lover time, app thread dump); (2) if it’s genuinely bursty load, raise somaxconn and the app backlog together. Verify: re-check that Recv-Q stays well below Send-Q under load and ListenOverflows stops climbing.
That’s the right call — the model read the queue overflow correctly, cross-referenced the dmesg overflow signal, and resisted the lazy “just bump somaxconn” answer by pointing out it does nothing if the app can’t drain the queue. It also gave me a verification: Recv-Q staying below Send-Q under load. The AI correlated the captures into a verdict; I confirmed the app-side stall and watched the queue behave before calling it fixed. Decode with AI, verify with your own eyes.
The takeaway
ss is the socket inspector netstat should have grown into — faster, with real TCP internals and a proper filter language, and uniquely good at the one thing that solves most “service won’t accept connections” incidents: reading a listener’s accept queue and backlog from a single line. Learn that Recv-Q and Send-Q mean queue-depth and backlog on a LISTEN socket (and bytes on an established one), and half your connection mysteries become one-line diagnoses. AI is excellent for correlating an ss summary, a state filter, and dmesg into a clear app-vs-kernel verdict — and for resisting the reflexive sysctl bump that fixes nothing. But you confirm the diagnosis under load and watch the queue drain yourself. Inspect with ss, reason with AI, verify with reality.
For where this fits, see troubleshooting Linux network connectivity layer by layer and modern Linux networking with ip and iproute2. The conntrack table exhaustion tuning prompt is a good next stop when the limit turns out to be connection tracking rather than the accept queue.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.