Linux & Shell guide · Last updated

How to Kill a Process Running on a Port

When your dev server fails with "Error: listen EADDRINUSE: address already in use :::3000" or "Port 8080 is already in use", another process is holding the port. On macOS and Linux, lsof -ti :3000 | xargs kill finds and stops it in one line. On Windows, netstat -ano | findstr :3000 shows the PID and taskkill /PID <pid> /F ends it. This guide covers those commands and the alternatives (ss, fuser, PowerShell's Get-NetTCPConnection, npx kill-port), explains why the error happens in the first place, and lists the cases where killing the process is the wrong fix.

Quick answer

Replace 3000 with your port. Try a normal kill first and only escalate to a forced kill if the process ignores it.

bash
# macOS / Linux
lsof -ti :3000 | xargs kill          # graceful (SIGTERM)
lsof -ti :3000 | xargs kill -9       # forced (SIGKILL) if it refuses

# Linux alternative
fuser -k 3000/tcp
powershell
# Windows (cmd or PowerShell)
netstat -ano | findstr :3000
taskkill /PID 12345 /F

Why "address already in use" happens

Only one process can listen on a given TCP port and address at a time. When a second program tries to bind the same port, the operating system rejects it and Node reports EADDRINUSE, Python raises OSError: [Errno 98] Address already in use (errno 48 on macOS), and Java throws BindException. The usual culprits are:

  • A previous run of the same dev server that did not exit, for example after closing a terminal tab, a crashed watcher, or a Ctrl+Z (which suspends the process instead of stopping it).
  • Another project you forgot was running on the same default port: 3000 for Next.js, Express and Rails, 5173 for Vite, 8080 for many Java and proxy servers, 8000 for Django.
  • A Docker container publishing the port, which shows up as com.docker.backend, docker-proxy or vpnkit rather than your app.
  • On macOS Monterey and later, AirPlay Receiver (the ControlCenter process) listens on ports 5000 and 7000. Turn it off in System Settings, General, AirDrop and Handoff, or use another port.
  • On Windows, Hyper-V and WSL reserve port ranges. That usually shows up as an access-permission error rather than EADDRINUSE; check with netsh interface ipv4 show excludedportrange protocol=tcp.

macOS: find and kill the process with lsof

lsof (list open files) is installed on every Mac. lsof -i :3000 shows every process with a connection on port 3000, including clients connected to it. To see only the listening server, filter by TCP state; -n and -P skip DNS and port-name lookups so the output is instant and shows numbers.

-t prints PIDs only, which is what you pipe into kill. Plain kill sends SIGTERM, which lets the process close files and connections cleanly. kill -9 sends SIGKILL, which cannot be caught, so use it only when SIGTERM does not work. If the process belongs to another user or to root, prefix the command with sudo.

bash
lsof -i :3000
# COMMAND   PID   USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
# node    48213  ayush   23u  IPv6  0x...       0t0  TCP *:hbci (LISTEN)

lsof -nP -iTCP:3000 -sTCP:LISTEN     # only the listener, numeric output
kill 48213                            # graceful
kill -9 48213                         # forced

# One-liners
kill $(lsof -ti :3000)
lsof -ti :3000,8080 | xargs kill      # several ports at once

Linux: lsof, ss and fuser

lsof works the same on Linux, though it is not installed on every minimal server or container image. ss from iproute2 is always available on modern distributions and replaces the older netstat. -l shows listening sockets, -t TCP, -n numeric and -p the owning process. Without sudo you only see the process names for sockets you own.

fuser (from psmisc) is the shortest route: fuser 3000/tcp prints the PID and fuser -k 3000/tcp kills it. By default -k sends SIGKILL, so pass -TERM for a graceful stop. If the port belongs to a system service such as nginx or Apache, stop it through its service manager instead (sudo systemctl stop nginx); otherwise systemd may simply restart it.

bash
sudo ss -ltnp 'sport = :8080'
# State  Recv-Q Send-Q Local Address:Port  Peer Address:Port Process
# LISTEN 0      511          0.0.0.0:8080       0.0.0.0:*     users:(("java",pid=2231,fd=9))

sudo ss -ltnp | grep ':8080'
sudo netstat -tulpn | grep ':8080'    # older systems (net-tools)

fuser 8080/tcp                        # print PID
fuser -k -TERM 8080/tcp               # graceful kill
sudo fuser -k 8080/tcp                # SIGKILL, any owner

sudo lsof -ti :8080 | xargs -r kill

Windows: netstat, taskkill and PowerShell

On Windows, netstat -ano lists connections with the owning process ID in the last column. Filter it with findstr and look for the line in the LISTENING state, then end that PID with taskkill. /F forces termination; without it Windows asks the program to close, which console apps such as Node often ignore. tasklist /FI "PID eq 12345" tells you what the process is before you kill it. Run the terminal as Administrator if access is denied.

Command Prompt

bat
netstat -ano | findstr :3000
:: TCP    0.0.0.0:3000    0.0.0.0:0    LISTENING    12345

tasklist /FI "PID eq 12345"
taskkill /PID 12345 /F
taskkill /IM node.exe /F       :: kill every node.exe (use with care)

PowerShell

Get-NetTCPConnection returns objects instead of text, so there is nothing to parse. Filter on -State Listen so you do not pick up PID 0 from connections in the TIME_WAIT state.

powershell
Get-NetTCPConnection -LocalPort 3000 -State Listen |
  Select-Object LocalAddress, LocalPort, OwningProcess

$procId = (Get-NetTCPConnection -LocalPort 3000 -State Listen).OwningProcess
Get-Process -Id $procId
Stop-Process -Id $procId -Force

Cross-platform: npx kill-port

If you work in JavaScript projects across operating systems, the kill-port npm package wraps the platform-specific commands. npx kill-port 3000 downloads it on first use and kills whatever listens on the port, on macOS, Linux and Windows alike. You can pass several ports, and some teams add it to a predev script so the dev server always starts on a free port. It is convenient, but it kills without asking what the process is, so it is best kept to local development.

bash
npx kill-port 3000
npx kill-port 3000 5173 8080
json
{
  "scripts": {
    "predev": "npx kill-port 3000",
    "dev": "next dev"
  }
}

When the port belongs to Docker

If lsof or netstat shows a Docker process, killing it would take down Docker itself or other containers. Find the container that publishes the port and stop that instead.

On Linux the listener is usually docker-proxy; on macOS and Windows it is the Docker Desktop backend process. In both cases docker ps shows the mapping in its PORTS column, such as 0.0.0.0:3000->3000/tcp. If the container belongs to a Compose project, run docker compose down in that project folder so it does not restart on its own because of a restart: always policy.

bash
docker ps --filter publish=3000
docker stop <container-id>

Alternatives to killing the process

Killing is a blunt fix. Before you do it, check what the process is: ending a database, a VPN client or a system service can cause more trouble than a busy port. Often the better solution is to run your app on another port, for example PORT=3001 npm run dev, next dev -p 3001, vite --port 5174 or python manage.py runserver 8001. Next.js and Vite will also offer the next free port automatically.

If your own server restarts too quickly after a crash and fails to bind, the old socket may be in TIME_WAIT. Servers can set the SO_REUSEADDR socket option to bind anyway; most frameworks already do. And if a suspended job is holding the port in your current terminal, jobs lists it and fg brings it back so you can stop it properly with Ctrl+C.

Warning

Avoid kill -9 and taskkill /F on databases and anything that writes files. A forced kill skips clean-up, can corrupt data files and leaves stale lock or PID files that block the next start.

Kill process on port: FAQ

Quick answers to common questions

How do I kill port 3000 on a Mac?

Run lsof -ti :3000 | xargs kill. If the process does not exit, run lsof -ti :3000 | xargs kill -9. Add sudo if the process belongs to another user.

How do I kill the process on port 8080 in Windows?

Run netstat -ano | findstr :8080 to get the PID from the last column, then taskkill /PID <pid> /F. In PowerShell, Stop-Process -Id (Get-NetTCPConnection -LocalPort 8080 -State Listen).OwningProcess -Force does it in one line.

What does EADDRINUSE mean?

It means another process is already listening on the address and port your program tried to use. Find it with lsof -i :PORT or netstat -ano, then stop it or run your app on a different port.

What is the difference between kill and kill -9?

kill sends SIGTERM, which asks the process to shut down cleanly. kill -9 sends SIGKILL, which ends it immediately with no clean-up. Always try plain kill first.

Why does lsof show nothing but the port is still in use?

The process probably belongs to another user or root, so run sudo lsof -i :PORT. It can also be a Docker container (check docker ps) or, on macOS, AirPlay Receiver on ports 5000 and 7000.

Related tools and references

More developer guides