How to Check Open Ports in Linux

Deepak Prasad
Tested on RHEL 10.2 (Coughlan)
Package iproute 6.17.0-2.el10.x86_64
lsof 4.98.0-7.el10.x86_64
nmap 7.92-5.el10.x86_64
nmap-ncat 7.92-5.el10.x86_64
net-tools 2.0-0.73.20160912git.el10.x86_64
Applies to Ubuntu, Debian, Kali Linux, Linux Mint, Pop!_OS, Raspberry Pi OS, elementary OS, Zorin OS, Parrot OS, MX Linux, RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, Fedora, Arch Linux
Privilege sudo or root for process names on sockets owned by other users; unprivileged ss and lsof may hide some PIDs
Scope Check listening TCP/UDP ports locally with ss and lsof, test reachability from another host with nc and nmap, and troubleshoot bind address versus firewall versus remote access. Does not cover opening firewall ports or full ss/netstat/nmap references.
Related guides ss command
lsof command
Test port connectivity
Open a port on Linux
netstat command

"Check whether a port is open" usually means one of two things: is a service listening on this Linux host, or can another machine actually reach that port? The first question belongs to ss and lsof on the server; the second needs a test from a client with nc or nmap.

Three common questions map to these checks:

text
What is listening on this server?     → sudo ss -tulnp
Which process owns port 8080?         → sudo ss -ltnp 'sport = :8080'  or  sudo lsof -nP -i :8080
Can another host reach TCP port 8080? → nc -zv SERVER 8080  or  nmap -p 8080 SERVER

Quick Reference: Check Open Ports in Linux

Task Command
List listening TCP and UDP sockets sudo ss -tulnp
List listening TCP ports sudo ss -ltnp
List UDP sockets sudo ss -lunp
Check a specific local port sudo ss -ltnp 'sport = :22'
Find the process using a port sudo lsof -nP -i :8080
List listening TCP processes sudo lsof -nP -iTCP -sTCP:LISTEN
Test one remote TCP port nc -zv SERVER PORT
Scan specific remote ports nmap -p 22,80,443 SERVER
Scan all TCP ports remotely nmap -p- SERVER
Legacy listening-port command sudo netstat -tulnp

Use ss when you are logged into the Linux host and need a current socket list. Use lsof when you need the owning process and PID. Use nc for a quick TCP connectivity probe from another machine. Use nmap when you need formal port state from outside the host. Keep netstat for legacy scripts and older systems where ss is unavailable.


Understand open, listening, closed, and filtered ports

These terms answer different questions. Mixing them up is why a port can appear in ss locally yet fail a remote connection test.

Listening locally means a process created a socket and is waiting for traffic. Confirm with:

bash
sudo ss -ltnp

Open from a remote scanner's perspective means a probe reached the target and found an application accepting connections on that port.

Closed means the host responded, but nothing is listening on that port.

Filtered means a firewall or other filter prevented the scanner from learning whether a service is listening.

For a typical TCP service, the relationship looks like this:

Situation Local ss Remote test
Service listening and reachable Listener shown Open or connect success
Service listening only on 127.0.0.1 Listener shown Not reachable remotely
Service listening but firewall blocks traffic Listener shown Filtered or timeout
Firewall allows port but nothing listens Nothing listening Closed
No listener and firewall drops traffic Nothing listening Filtered or timeout

A firewall rule that permits TCP/8080 only allows packets to reach the host. A service must still listen on TCP/8080 before a normal connection succeeds. Do not describe a permitted-but-unused port as "open" in the port-scanning sense.


List listening ports with ss

The ss command is the preferred modern tool for many socket-listing tasks traditionally handled by netstat and reads socket state from the kernel. Start with every listening TCP and UDP socket:

bash
sudo ss -tulnp

Sample output:

output
Netid State  Recv-Q Send-Q Local Address:Port  Peer Address:PortProcess
udp   UNCONN 0      0      0.0.0.0:5353       0.0.0.0:*    users:(("avahi-daemon",pid=1101,fd=12))
tcp   LISTEN 0      128    0.0.0.0:22         0.0.0.0:*    users:(("sshd",pid=1202,fd=7))
tcp   LISTEN 0      511    127.0.0.1:43879    0.0.0.0:*    users:(("node",pid=2407,fd=19))

The flags matter:

  • -t — TCP sockets
  • -u — UDP sockets
  • -l — listening sockets only
  • -n — numeric addresses and ports (no DNS lookups)
  • -p — process name and PID when you run with sufficient privilege

Netid is the protocol, State is the socket state, Local Address:Port is where the service accepts traffic, and the Process column names the listener when -p can resolve it. TCP listeners normally show LISTEN; UDP sockets usually show UNCONN because UDP is connectionless. Do not expect LISTEN on UDP rows.

To list TCP listeners only:

bash
sudo ss -ltnp

Sample output:

output
State  Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0      128    0.0.0.0:22        0.0.0.0:*    users:(("sshd",pid=1202,fd=7))
LISTEN 0      511    *:80              *:*          users:(("httpd",pid=1228,fd=4),("httpd",pid=1295,fd=4))

UDP sockets use the same tool with -u instead of -t:

bash
sudo ss -lunp

Sample output:

output
State  Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
UNCONN 0      0      0.0.0.0:5353      0.0.0.0:*    users:(("avahi-daemon",pid=1101,fd=12))
UNCONN 0      0      127.0.0.1:323     0.0.0.0:*    users:(("chronyd",pid=1102,fd=4))

0.0.0.0:22 means SSH accepts IPv4 on all interfaces; 127.0.0.1:323 is chrony bound to loopback only.


Check whether a specific port is listening

Filter ss when you care about one port instead of the full table. For SSH on TCP/22:

bash
sudo ss -ltnp 'sport = :22'

Sample output:

output
State  Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0      128    0.0.0.0:22        0.0.0.0:*    users:(("sshd",pid=1202,fd=7))
LISTEN 0      128       [::]:22           [::]:*    users:(("sshd",pid=1202,fd=8))

Matching rows mean a listener exists on that port. Empty output means nothing matched the filter.

The native filter is preferable to piping through grep, but this fallback works on any host:

bash
sudo ss -ltnp | grep ':22 '

Swap the port number for any check you need:

bash
sudo ss -ltnp 'sport = :8080'

When no process listens on 8080, ss prints only the header row and exits. That answers "is this port in use?" without scanning the full socket table.


Find which process is using a port

ss with -p is the fastest way to tie a port to a PID on the local host:

bash
sudo ss -ltnp 'sport = :8080'

Sample output (after starting a test listener on 8080):

output
State  Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0      5      127.0.0.1:8080    0.0.0.0:*    users:(("python3",pid=55869,fd=5))

The users:(("python3",pid=55869,fd=5)) field names the process, PID, and file descriptor.

lsof is often clearer when you want a dedicated process table:

bash
sudo lsof -nP -i :8080

Sample output:

output
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
python3 55869 root    5u  IPv4 513532      0t0  TCP 127.0.0.1:8080 (LISTEN)

-i :8080 can also show established connections involving port 8080, not only a listening socket. For the TCP listener only:

bash
sudo lsof -nP -iTCP:8080 -sTCP:LISTEN

-n skips hostname resolution, -P keeps numeric ports, and -i selects network files. To list every TCP listener in one shot:

bash
sudo lsof -nP -iTCP -sTCP:LISTEN

Sample output:

output
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
sshd    1202 root    7u  IPv4  11499      0t0  TCP *:22 (LISTEN)
httpd   1228 root    4u  IPv6   9954      0t0  TCP *:80 (LISTEN)

Flag-level detail for lsof lives in the lsof command cheat sheet. This section only answers which process owns port X.


Check whether a port is open from another Linux host

ss reports what listens on the server. To learn whether a client can reach the service, run a test from another machine.

Example lab:

text
Client (192.168.1.10)  --->  Server (192.168.1.20, SSH on TCP/22)

From the client, probe one TCP port with nc:

bash
nc -zv 192.168.1.20 22

On this host, testing loopback shows the same success and failure shapes:

bash
nc -zv 127.0.0.1 22

Sample output:

output
Ncat: Connected to 127.0.0.1:22.
Ncat: 0 bytes sent, 0 bytes received in 0.04 seconds.

A closed port on a reachable host usually returns connection refused:

bash
nc -zv 127.0.0.1 59999

Sample output:

output
Ncat: Connection refused.

Connection refused typically means the packet reached the target, but no TCP service accepted the connection on that port. Connection timed out may indicate filtering, routing problems, or an unreachable host, not always a host firewall. telnet HOST PORT can test a TCP connection when Telnet is installed, but nc is generally more convenient for port checks. For a full client-to-server workflow, see test port connectivity.


Scan open ports on a remote host with nmap

nmap reports port state from the scanner's perspective. Run these from the client host in the lab (192.168.1.10) against the server (192.168.1.20). Check one port:

bash
nmap -p 22 192.168.1.20

Sample output:

output
PORT   STATE SERVICE
22/tcp open  ssh

Scan several ports at once:

bash
nmap -p 22,80,443 192.168.1.20

Sample output:

output
PORT    STATE  SERVICE
22/tcp  open   ssh
80/tcp  open   http
443/tcp closed https

A default nmap run scans its built-in set of common ports, not all 65,535 TCP ports. To scan every TCP port on the server:

bash
nmap -p- 192.168.1.20
Nmap state Meaning
open Application is accepting connections or packets
closed Host responds, but no application is listening
filtered Filtering prevents determining open versus closed
open|filtered Nmap cannot distinguish open from filtered

This article stops at everyday port checks. Advanced scan types and service-version enumeration belong in dedicated Nmap material, not here.


Check UDP ports

UDP is connectionless, so local and remote checks look different from TCP.

List local UDP sockets:

bash
sudo ss -lunp

Rows show UNCONN rather than TCP's LISTEN. That is normal for UDP listeners.

From another host, probe UDP with Nmap (often requires root on the scanner):

bash
sudo nmap -sU -p 53 192.168.1.20

Sample output:

output
PORT   STATE  SERVICE
53/udp closed domain

UDP scanning is less definitive than TCP. No response may appear as open|filtered because the scanner cannot tell whether the port accepted the probe or a filter dropped it.


Check listening ports with netstat (legacy systems)

netstat still appears in older scripts and minimal images. The listening-port view parallels ss:

bash
sudo netstat -tulnp

Sample output:

output
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1202/sshd
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN      1194/cupsd
tcp6       0      0 :::22                   :::*                    LISTEN      1202/sshd

Prefer ss on current Linux systems when it is available. Flag reference and scripting notes live in the netstat command cheat sheet.


Why a port listens locally but is not reachable remotely

When sudo ss -ltnp shows the port but nc -zv SERVER PORT fails from another machine, work through these checks in order.

Bind address. 127.0.0.1:8080 accepts IPv4 traffic only through loopback. 0.0.0.0:8080 listens on all IPv4 interfaces, while [::]:8080 listens on all IPv6 interfaces. Whether an IPv6 wildcard socket also accepts IPv4 connections depends on the application's socket configuration and system settings. The bind address controls where the application accepts connections, not whether a firewall permits the port.

Host firewall. firewalld, nftables, or UFW may block traffic even when a service listens on 0.0.0.0. Opening a port is covered in open a port on Linux, not here.

Upstream controls. Cloud security groups, router ACLs, or another firewall between client and server can block traffic before it reaches the host.

Service health. Confirm the listener still exists:

bash
sudo ss -ltnp 'sport = :8080'

Replace 8080 with the port you want to verify.

Test location. A loopback nc test and a test from another subnet answer different questions. Run the probe from the network path your users actually use.


Summary

Use ss to find listening TCP and UDP sockets on the host you are logged into, lsof when you need the process and PID behind a port, nc for a quick TCP probe from another machine, and nmap when you need formal remote port state. Keep netstat for legacy compatibility when ss is not an option.

A service listening locally, a firewall permitting traffic, and a port being reachable from another host are related but separate conditions. Start with sudo ss -tulnp on the server, then verify from the client with nc or nmap when reachability is the question.


References

Omer Cakmak

Linux Administrator

Highly skilled at managing Debian, Ubuntu, CentOS, Oracle Linux, and Red Hat servers. Proficient in bash scripting, Ansible, and AWX central server management, he handles server operations on OpenStack, KVM, Proxmox, and VMware.

  • Debian
  • Ubuntu
  • Linux
  • Red Hat Enterprise Linux
  • Shell Script
  • System Administration