ss (socket statistics) shows network connections and listening sockets. It replaced netstat on modern distributions: it’s faster (reading directly from the kernel), has powerful filters, and is installed by default as part of iproute2.

The command you’ll use most

sudo ss -tulpn
  • -t TCP, -u UDP
  • -l listening sockets
  • -p owning process (sudo needed for other users’ processes)
  • -n numeric — no DNS or service name lookups
Netid State  Recv-Q Send-Q  Local Address:Port  Peer Address:Port Process
tcp   LISTEN 0      511           0.0.0.0:80         0.0.0.0:*     users:(("nginx",pid=812,fd=6))
tcp   LISTEN 0      151         127.0.0.1:3306       0.0.0.0:*     users:(("mariadbd",pid=901,fd=19))
tcp   LISTEN 0      4096                *:22               *:*     users:(("sshd",pid=701,fd=3))

0.0.0.0 or * = all interfaces (reachable from outside if the firewall allows); 127.0.0.1 = local only. See check open ports.

For a LISTEN socket, Send-Q is the backlog size and Recv-Q the number of connections waiting to be accepted. A Recv-Q near Send-Q means the application can’t accept connections fast enough.

Established connections

ss -tn                       # TCP connections (established by default without -a)
ss -tna                      # all TCP sockets, any state
ss -tnp state established    # with processes

Filter by port

ss -tn 'sport = :443'                    # local port 443 (incoming HTTPS)
ss -tn 'dport = :5432'                   # remote port 5432 (outgoing to PostgreSQL)
ss -tn '( sport = :80 or sport = :443 )'
ss -tlnp 'sport = :8080'                 # who's listening on 8080

Filter by address

ss -tn dst 203.0.113.5
ss -tn src 10.0.0.0/24
ss -tn 'dst 203.0.113.5 and dport = :22'

Filter by state

ss -tn state established
ss -tn state time-wait
ss -tn state syn-recv            # half-open — many could indicate a SYN flood
ss -tn state close-wait          # app didn't close the socket — possible bug

Counting connections

ss -s                                                       # summary
ss -tn state established '( sport = :443 )' | tail -n +2 | wc -l   # HTTPS connections
ss -tn state established | awk 'NR>1 {print $4}' | cut -d: -f1 | sort | uniq -c | sort -rn | head

The last line lists the remote IPs with the most connections — useful during a traffic spike or attack. (For IPv6 addresses, split on the last colon instead.)

Extra detail

ss -tni           # TCP internals: RTT, congestion window, retransmits
ss -tm            # socket memory usage
ss -to            # timers (keepalive, retransmission)
ss -x             # Unix domain sockets (PHP-FPM, MySQL socket…)
ss -xlp | grep php

ss -tni is a hidden gem for network troubleshooting: high rtt values or many retrans point to latency or packet loss on that connection. Check which congestion algorithm is in use (cubic, bbr) — see TCP BBR.

netstat → ss cheat sheet

netstat still exists in the net-tools package, but if you know the old commands:

netstat ss
netstat -tulpn ss -tulpn
netstat -an ss -an
netstat -tn ss -tn
netstat -s ss -s (summary; detailed counters: nstat)
netstat -r ip route
netstat -i ip -s link
netstat -g ip maddr

Typical troubleshooting questions

“Address already in use” when starting a service:

sudo ss -tlnp 'sport = :80'

Is my app listening on the right interface?

sudo ss -tlnp | grep node

If it shows 127.0.0.1:3000, it can’t be reached from outside — by design or by mistake.

Thousands of TIME-WAIT sockets? Normal on busy servers making many short outgoing connections; it becomes a problem only if you exhaust local ports. Connection reuse (keepalive, pooling) is the real fix.

Many CLOSE-WAIT sockets for one process? The application isn’t closing connections — a bug or a hung worker.

Quick reference

Task Command
Listening ports + processes ss -tulpn
Established TCP ss -tn state established
One port ss -tn 'sport = :443'
One remote host ss -tn dst IP
Summary ss -s
TCP details ss -tni
Unix sockets ss -xlp

Related: lsof, ip command and network troubleshooting on Linux.

  • Linux
  • Networking
  • Command Line