Developer Tools September 23, 2024 Aditya Rawas

How to Kill a Process and Free Up a Port on Mac, Linux & Windows

You’ve started your local dev server and hit a dreaded error: “port 3000 is already in use.” It happens to every developer. Here’s the fastest way to find and kill the offending process on any operating system — macOS, Linux, Windows, or WSL.


Quick Reference Cheat Sheet

OSFind PIDKill GracefullyKill Forcefully
macOS / Linuxsudo lsof -i :PORTkill PIDkill -9 PID
Linux onlyfuser PORT/tcpkill PIDfuser -k PORT/tcp
Any (by name)pgrep process-namepkill process-namepkill -9 process-name
Windows (CMD)netstat -ano | findstr :PORTtaskkill /PID PID /F
Windows (PS)Get-Process -Id (Get-NetTCPConnection -LocalPort PORT).OwningProcessStop-Process -Id PID -Force

Understanding SIGTERM vs SIGKILL

Before reaching for -9, it helps to understand what signals you’re sending.

  • kill PID sends SIGTERM (signal 15) — a polite request to terminate. The process can catch this signal, clean up open files, flush buffers, and exit gracefully. Always try this first.
  • kill -9 PID sends SIGKILL (signal 9) — an immediate, unblockable termination issued by the kernel. The process has no chance to clean up. Use this only when SIGTERM doesn’t work.

Data loss risk: Forceful termination can corrupt in-progress writes or leave lock files behind. Always try graceful termination first.


macOS

Step 1: Find the Process ID (PID)

sudo lsof -i :3000

Replace 3000 with your actual port number. The output looks like:

COMMAND   PID   USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
node     8432  aditya  23u  IPv6  0xabc     0t0  TCP *:3000 (LISTEN)

Copy the PID from the second column — 8432 in this example.

Step 2: Kill the Process

kill 8432

If the process doesn’t terminate within a few seconds, force it:

kill -9 8432
# or if it's owned by another user:
sudo kill -9 8432

One-Liner (macOS)

Skip the two-step lookup and kill in a single command:

sudo kill -9 $(lsof -t -i:3000)

lsof -t outputs only the PID, which gets passed directly to kill.


Linux

Option 1: lsof (same as macOS)

sudo lsof -i :3000

Then kill by PID:

kill PID
# or forcefully:
kill -9 PID

Option 2: fuser (Linux-specific, faster)

fuser is built for exactly this — finding what’s using a file or port:

fuser 3000/tcp

This prints the PID directly. To kill it in one step:

fuser -k 3000/tcp

Add -9 to force kill:

fuser -k -9 3000/tcp

Option 3: Kill by Process Name with pkill

If you know the process name (e.g., node, python, ruby), skip the PID lookup entirely:

pkill node
# or forcefully:
pkill -9 node

To see which processes pkill would target without actually killing them:

pgrep -l node

This lists the PID and name of every matching process so you can confirm before killing.

Option 4: Live Process View with top / htop

For a general overview of all running processes:

top
# or the more readable version (install separately):
htop

Press k inside top to kill a process by PID without leaving the interface.


Windows

Command Prompt

Step 1: Find the PID

netstat -ano | findstr :3000

Output:

TCP    0.0.0.0:3000    0.0.0.0:0    LISTENING    8432

The last column is the PID (8432).

Step 2: Kill the Process

taskkill /PID 8432 /F

The /F flag forces termination (equivalent to SIGKILL). Verify the port is free:

netstat -ano | findstr :3000

If nothing is returned, the port is free.

PowerShell (One-Liner)

PowerShell lets you combine both steps:

Stop-Process -Id (Get-NetTCPConnection -LocalPort 3000).OwningProcess -Force

Or to see the process name before killing:

Get-Process -Id (Get-NetTCPConnection -LocalPort 3000).OwningProcess

WSL (Windows Subsystem for Linux)

If you’re running a server inside WSL and the port appears busy from Windows (or vice versa), the process may be running in a different network namespace.

Check inside WSL:

sudo lsof -i :3000
# or
fuser 3000/tcp

Check from Windows side (if WSL process is exposed):

netstat -ano | findstr :3000

If the port is occupied by a Windows process that’s interfering with your WSL server, kill it from the Windows side using taskkill.


Troubleshooting

”Port still in use” after killing

The process may have spawned child processes. Kill the entire process tree:

# Linux / macOS — kill process and all children
kill -9 -PID
# Note the negative sign before PID — this sends SIGKILL to the entire process group

On Windows:

taskkill /PID 8432 /F /T

The /T flag terminates child processes too.

”Permission denied” when killing

The process is owned by root or another user. Use sudo:

sudo kill -9 PID

“No such process” error

The process already terminated on its own, but the OS hasn’t released the port yet (TIME_WAIT state). Wait 30–60 seconds and try again. If the issue persists, you can reuse the port immediately with socket option SO_REUSEADDR in your server code.

Can’t find PID with lsof on macOS

Make sure you’re using sudo. Without it, lsof may not have permission to inspect all sockets:

sudo lsof -i :3000

Best Practices

SituationRecommended Command
First attempt, unknown processkill PID (SIGTERM)
Process ignores SIGTERMkill -9 PID (SIGKILL)
Know the process namepkill process-name
Port busy on Linux, want it fastfuser -k PORT/tcp
Windows CMDtaskkill /PID PID /F
Windows PowerShellStop-Process -Id PID -Force
Kill process + childrenkill -9 -PGID (Linux) / taskkill /PID PID /F /T (Windows)

These commands belong in every developer’s muscle memory. Bookmark this page for the next time a zombie process is holding your port hostage.

Aditya Rawas

Written by

Aditya Rawas

Full-stack engineer writing deep-dives on JavaScript, TypeScript, React, AWS, Docker, and Kubernetes. Passionate about making complex engineering concepts accessible to developers at every level.