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
-tTCP,-uUDP-llistening sockets-powning process (sudo needed for other users’ processes)-nnumeric — 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.