How to Check Open Ports in Linux: ss vs netstat
Check open ports in Linux using ss and netstat — with real command examples, output explanation, and when to use each tool in production troubleshooting.
How to Check Open Ports in Linux: ss vs netstat (With Real Examples)
If a service isn't reachable or you need to audit what's exposed on a server, checking open ports is step one. Both ss and netstat do the job — but ss is faster, more accurate, and pre-installed on every modern Linux system.
TL;DR
ss -tlnp # TCP listening ports with process names (use this first)
ss -ulnp # UDP listening ports
netstat -tlnp # same output, older syntax
ss vs netstat: Which One to Use
netstat comes from the deprecated net-tools package. On minimal installs (Docker containers, cloud images) it's often missing. ss reads directly from the kernel socket layer — it's faster and always available.
| Feature | ss | netstat |
|---|---|---|
| Pre-installed | ✅ Always | ❌ Often missing |
| Speed | Fast | Slower |
| Actively maintained | ✅ | ❌ Deprecated |
| Same basic flags | ✅ | ✅ |
Use ss. Learn netstat for legacy systems you don't control.
Check All Open TCP Ports
ss -tlnp
Flags:
-t— TCP only-l— listening sockets only-n— show port numbers, not service names-p— show process name and PID
Output:
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1023,fd=3))
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=2341,fd=6))
LISTEN 0 128 127.0.0.1:5432 0.0.0.0:* users:(("postgres",pid=3012,fd=4))
Reading the Output
The Local Address:Port column is what matters:
0.0.0.0:80— listening on all interfaces, reachable from anywhere127.0.0.1:5432— localhost only, not externally accessible[::]:22— all IPv6 interfaces
This distinction matters for security. A database bound to 0.0.0.0 instead of 127.0.0.1 is exposed to every network interface.
Real Examples
Check if a specific port is open
ss -tlnp | grep :8080
# Nothing returned = nothing listening on 8080
# Output returned = something is bound to that port
Check both TCP and UDP
ss -tlunp
# -u adds UDP sockets
Check with netstat (if ss is unavailable)
netstat -tlnp
netstat -tlnp | grep :3306 # is MySQL exposed?
Check active connections (not just listeners)
ss -tnp state established
# Shows who is currently connected, not just what's listening
Count connections to a port
ss -tnp state established dport :443 | wc -l
Security audit — what's exposed externally?
# Everything NOT bound to localhost
ss -tlnp | grep -v '127\.0\.0\.1' | grep -v '\[::1\]'
Output Explanation: What Each Column Means
State = socket state (LISTEN, ESTABLISHED, TIME-WAIT)
Recv-Q = bytes received but not yet read by the app
Send-Q = bytes queued to send (high = slow consumer or congestion)
Local Address:Port = what this machine is listening on
Peer Address:Port = remote side (0.0.0.0:* = any remote)
Process = pid and command name
Recv-Q > 0 on a LISTEN socket means the accept backlog is filling up — your app is slower than incoming connections. That's a problem.
Real-World Use Case: "Address Already in Use"
Service fails to start with bind: address already in use.
# Find what's holding the port
ss -tlnp | grep :8080
# Output: users:(("oldapp",pid=9901,fd=8))
# Check if it should be running
ps -p 9901 -o comm,stat
# Kill it if it's stale
kill -15 9901
# Confirm port is free
ss -tlnp | grep :8080
# No output = port is available
Common Mistakes
Mistake 1: Using netstat on a minimal container
It's not installed. Use ss — it's always there.
Mistake 2: Assuming a listening port means it's reachable
The service could be bound to 127.0.0.1. Check the local address column before assuming firewall issues.
Mistake 3: Not using -n
Without -n, ss tries to resolve port numbers to service names (http, ssh). That's slower and hides the actual port number when troubleshooting non-standard ports.
Mistake 4: Forgetting -p needs root for process names
sudo ss -tlnp # shows process names for all sockets
ss -tlnp # may show (null) for sockets owned by other users
Pro Tips
# Watch port connections in real time
watch -n 1 'ss -tlnp | grep :80'
# Find what port a PID is using
ss -tlnp | grep pid=1234
# Socket summary (total counts by state)
ss -s
# Check TIME-WAIT buildup (causes 502s under load)
ss -tn state time-wait | wc -l
# Show sockets with extended info (timers, etc.)
ss -tnoe
Conclusion
ss -tlnp is the command. Use it every time. It tells you what's listening, on which interface, and which process owns it — in one line.
The interface binding (0.0.0.0 vs 127.0.0.1) is the detail that catches most engineers off guard. A port being open doesn't mean it's accessible remotely. Check the local address column.
Also useful: Check Running Processes in Linux — pair port checks with process investigation. strace, lsof, and ss: The Trio That Solves Every Mystery — deeper socket-level debugging.