Checking Open Ports on Linux
Checking open ports tells you what services are accepting connections on your system. This is useful for security audits, debugging connectivity, and verifying firewall rules. There are several tools for this: ss for local socket state, lsof for process details, nmap for scanning from outside, and fuser for quick port-to-process lookups.
ss: the standard tool for local socket inspection
ss (socket statistics) replaces the older netstat. Use it to see what is listening on your own machine.
# Show all listening TCP ports
ss -tlnp
# Show all listening UDP ports
ss -ulnp
# Show both TCP and UDP
ss -tlnpu
# Show all connections (not just listening)
ss -tnp
# Flag breakdown:
# -t TCP sockets
# -u UDP sockets
# -l listening sockets only
# -n show port numbers, not service names
# -p show process name and PID
# Filter for a specific port
ss -tlnp | grep :80
ss -tlnp | grep ':443\b'
# Show connection state counts
ss -s
# Show all sockets including Unix domain sockets
ss -a
# Show socket memory usage
ss -tm
Reading ss 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=1234,fd=3))
LISTEN 0 511 127.0.0.1:5432 0.0.0.0:* users:(("postgres",pid=5678,fd=7))
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=9012,fd=6))
0.0.0.0:22— sshd listening on all interfaces, port 22 (reachable from network)127.0.0.1:5432— postgres listening only on loopback (local access only)0.0.0.0:80— nginx listening on all interfaces (reachable from network)Recv-Q / Send-Q— receive and send queue sizes; high numbers may indicate backpressure
lsof: file and socket info per process
lsof (list open files) shows all open files, including network sockets. It is useful for finding exactly which process owns a connection.
# Show all internet sockets
sudo lsof -i
# Show processes using a specific port
sudo lsof -i :80
sudo lsof -i :443
sudo lsof -i :22
# Show TCP only
sudo lsof -i TCP
# Show listening sockets
sudo lsof -i -sTCP:LISTEN
# Show all connections for a specific process
sudo lsof -i -p 1234
# Show by process name
sudo lsof -i -c nginx
sudo lsof -i -c sshd
# Show connections to a remote host
sudo lsof -i @192.168.1.1
# Combine: nginx listening on 80 or 443
sudo lsof -i TCP:80,443 -sTCP:LISTEN
lsof output format
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nginx 9012 root 6u IPv4 12345 0t0 TCP *:http (LISTEN)
nginx 9013 www-data 6u IPv4 12345 0t0 TCP *:http (LISTEN)
FD— file descriptor number and access mode (u = read+write)TYPE— IPv4 or IPv6NAME— the address and port (here*:http= all interfaces, port 80)
fuser: quick port lookup
fuser shows which process is using a specific port. Faster than lsof when you just want the PID.
# Find what is using TCP port 80
sudo fuser 80/tcp
# Find what is using UDP port 53
sudo fuser 53/udp
# Show process name as well (-v verbose)
sudo fuser -v 80/tcp
# Multiple ports at once
sudo fuser 80/tcp 443/tcp 22/tcp
# Kill whatever is using a port (use carefully)
sudo fuser -k 8080/tcp
nmap: scanning from the outside
nmap scans ports from a network perspective. Use it to check what is visible to the outside world, or to scan other hosts.
# Scan common ports on a host (requires nmap installed)
nmap hostname
nmap 192.168.1.10
# Scan a specific port
nmap -p 80 hostname
nmap -p 443 hostname
# Scan a range of ports
nmap -p 1-1000 hostname
nmap -p 22,80,443,8080 hostname
# Scan all 65535 ports
nmap -p- hostname
# Show service version detection
nmap -sV -p 80,443 hostname
# Quick scan of common ports (faster)
nmap -F hostname
# Scan from localhost (same as ss but through the network stack)
nmap -p- localhost
sudo nmap -sU -p- localhost # UDP scan (requires root)
# Scan a subnet
nmap -sn 192.168.1.0/24 # ping scan (find live hosts)
nmap -p 22,80 192.168.1.0/24 # port scan a subnet
nmap vs ss
| Situation | Use |
|---|---|
| What is listening on my machine? | ss -tlnp |
| What process owns port X on my machine? | ss -tlnp or lsof -i :X |
| What ports are visible from the network? | nmap localhost or nmap <server-ip> from outside |
| What ports are open on a remote host? | nmap hostname |
| Is port X reachable from here? | nc -zv hostname X or nmap -p X hostname |
nc (netcat): quick TCP/UDP port tests
# Test if a TCP port is open (exit code 0 = open, nonzero = closed/refused)
nc -zv hostname 80
nc -zv hostname 443
nc -zv hostname 22
# Test multiple ports
nc -zv hostname 80 443 8080
# Test with a timeout (seconds)
nc -zv -w 3 hostname 80
# Test UDP (less reliable, no handshake)
nc -zuv hostname 53
# Bash built-in port test (no nc needed)
(echo > /dev/tcp/hostname/80) 2>/dev/null && echo "open" || echo "closed"
Checking ports on a firewall vs application level
There are two distinct places where a port can be “closed”:
- Application not listening: the service is not running or not bound to that port.
ss -tlnpwill not show it. - Firewall blocking: the service is listening but the firewall drops packets before they reach it.
ssshows it listening, butnmapfrom outside shows it as filtered.
# Check application-level (is anything listening?)
ss -tlnp | grep :80
# Check firewall rules
sudo nft list ruleset # nftables
sudo iptables -L -n -v # iptables
sudo ufw status verbose # ufw
# Check if the firewall is the issue by temporarily testing from localhost
curl -s --max-time 2 http://localhost:80
# If this works but external access fails, the firewall is blocking
Monitoring connections over time
# Watch ss output update every 2 seconds
watch -n 2 'ss -tlnp'
# Watch connection count per state
watch -n 1 'ss -s'
# See connections being made in real time (tcpdump)
sudo tcpdump -i eth0 port 80 -n
# See established connections
ss -tnp | grep ESTAB
# Count connections by state
ss -tn | awk 'NR>1 {print $1}' | sort | uniq -c
# See which remote IPs are connected
ss -tnp | grep ESTAB | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn
Frequently Asked Questions
What is the difference between ss and netstat for checking ports?
ss (socket statistics) is the modern replacement for netstat. Both display socket and network connection information, but ss is part of the iproute2 package (maintained and standard on all current Linux distributions), while netstat comes from net-tools (deprecated and absent from minimal installs). ss is faster for large numbers of connections because it reads data directly from the kernel via Netlink sockets rather than parsing /proc. The flags differ slightly but the concepts are the same: ss -tlnp shows TCP listening sockets with port numbers and process info, the same information that netstat -tlnp provides.
What does it mean for a port to be “listening”?
A port is listening when a process has bound to it and called listen(), indicating it is ready to accept incoming connections. You can think of a listening port as an open door: the process is waiting there and will respond when someone connects. A port can also be in ESTABLISHED state (an active connection is open), TIME_WAIT (connection recently closed, kernel holding the socket briefly), or other states. For security purposes, the set of listening ports determines your attack surface: every listening port is a potential entry point for a network attacker.
How do I check if a specific port is open on a remote host?
Use nmap: nmap -p 80 hostname checks if port 80 is open. nc -zv hostname 80 (netcat) attempts a TCP connection and reports success or failure. curl -s —max-time 3 http://hostname:80 tests an HTTP port. For a quick TCP check without installing anything, use bash built-in: (echo > /dev/tcp/hostname/80) 2>/dev/null && echo “open” || echo “closed”. Note that these test TCP; UDP ports require nmap -sU (requires root) because UDP has no handshake to complete.
What is the difference between 0.0.0.0 and 127.0.0.1 in listening addresses?
When a service listens on 0.0.0.0 (or :: for IPv6), it accepts connections on all network interfaces — including the network-facing ones. This means the service is accessible from the network. When a service listens on 127.0.0.1, it only accepts connections from the same machine (the loopback interface). Services that only need to be accessed locally (databases, caches, internal APIs) should bind to 127.0.0.1 rather than 0.0.0.0 to reduce exposure. Misconfigured services binding to 0.0.0.0 when they should be on 127.0.0.1 is a common security mistake.
How do I find which process is using a specific port?
The most direct way is ss -tlnp | grep :80 or ss -tlnp | grep “LISTEN.*:80”, which shows the port alongside the process name and PID. Alternatively, fuser 80/tcp shows the PID using port 80. lsof -i :80 shows the process with more detail. On most systems these require sudo to see processes owned by other users. If ss shows a port is listening but lsof/fuser show nothing, you may not have permission to see the process and should re-run with sudo.
What well-known ports should I expect to see on a Linux server?
Common legitimate listening ports include: 22 (SSH), 25/587/465 (mail), 53 (DNS), 80 (HTTP), 443 (HTTPS), 3306 (MySQL), 5432 (PostgreSQL), 6379 (Redis), 27017 (MongoDB), 8080/8443 (alternative HTTP/HTTPS). Ports you should investigate if unexpected: anything above 1024 that you did not explicitly configure, repeated connection attempts to unusual ports in firewall logs, and services bound to 0.0.0.0 that should only be local. Well-known ports (0-1023) require root to bind; registered ports (1024-49151) are commonly used by software; dynamic/ephemeral ports (49152-65535) are used for outbound connections.