Back to Blog

How to Find Which Application Is Using a Port

How to Find Which Application Is Using a Port
Command of the Day
fuser -k 8080/tcp

What it does: Finds and forcefully kills the process currently occupying TCP port 8080.

One of the most frequent errors encountered when launching a web server (Nginx/Apache), a Node.js API, or a Docker container is: bind: address already in use or Error: listen EADDRINUSE: address already in use :::3000.

This happens when another running process is already bound to that network port. In this guide, you will learn how to find the exact application holding the port and resolve the conflict.


1. Finding the Application Using lsof

The lsof command is the cleanest and most direct tool for inspecting port bindings.

Search by Port Number

sudo lsof -i :80

(Replace 80 with whatever port you are checking, e.g., 3000, 8080, 25565).

Example Output:

COMMAND   PID     USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nginx    1420     root    6u  IPv4  23984      0t0  TCP *:80 (LISTEN)
nginx    1421 www-data    6u  IPv4  23984      0t0  TCP *:80 (LISTEN)

In this example:

  • COMMAND: nginx
  • PID: 1420
  • USER: root

2. Finding the Application Using ss

If lsof is not installed on your server:

sudo ss -lptn 'sport = :80'

Or use a general grep filter:

sudo ss -tulpn | grep ':80 '

3. Finding and Killing Instantly with fuser

The fuser tool can identify and even terminate the process occupying a specific TCP/UDP port in one command.

Check Process on Port:

sudo fuser 80/tcp

Output:

80/tcp:               1420  1421

Kill the Process Occupying the Port:

sudo fuser -k 80/tcp

[!WARNING] Using fuser -k immediately sends a kill signal to all processes attached to that port. Use with caution on production servers!


4. How to Handle the Conflicting Service

Once you have identified the PID and application name:

Case 1: An Abandoned or Zombie Background Script

If it is a test script or node process that was left running:

kill -15 <PID>

Case 2: A Managed Systemd Service (e.g., Apache vs Nginx)

If Apache is occupying port 80 and preventing Nginx from starting:

sudo systemctl stop apache2
sudo systemctl disable apache2
sudo systemctl start nginx

Case 3: A Docker Container

If the port is held by docker-proxy:

docker ps --filter "publish=80"
docker stop <container_id>

Common Mistakes

  • Running port commands without sudo: Without administrative privileges, ss and lsof will hide process names and PIDs belonging to other system users.
  • Killing the wrong service: Always verify the COMMAND and USER before issuing kill or fuser -k.

Troubleshooting

  • Port appears closed in ss, but app still throws EADDRINUSE: Check if the application is trying to bind to an IPv6 address (:::80) where an IPv6 listener is active, or check if the socket is stuck in TIME_WAIT state (ss -tan | grep TIME-WAIT).
  • Cannot kill process (PID not dying): Check if the process is managed by systemd or pm2 with automatic restart policies. If so, stop the supervisor directly (sudo systemctl stop <service> or pm2 stop <app>).

Best Practices

  • Standardize port allocations across your development and production environments.
  • Use reverse proxies like Nginx or Traefik on ports 80/443 so multiple backend applications can run on internal ports (e.g., 3000, 3001, 8080) behind domain names.

Frequently Asked Questions

Why does ss -tulpn not show process names when run as a standard user?

Linux security policy forbids unprivileged users from viewing file descriptors and socket handles owned by other users or the root account.

How do I check UDP ports specifically?

Use sudo ss -ulpn 'sport = :53' or sudo lsof -i udp:53.


Conclusion

Resolving port conflicts is quick and simple once you know how to leverage lsof and ss. Use these tools to keep your RivinCloud VPS services organized and running smoothly!