How to kill the process on a port on Mac
One command finds the process, one stops it. Here’s the safe order to do it in, shortcuts for doing it often, and what to do when a process won’t stay dead.
By Anmol Sethi · Updated
The one-liner
Find the PID listening on the port and send it SIGTERM:
lsof -ti tcp:3000 -sTCP:LISTEN | xargs kill-t prints only PIDs, and -sTCP:LISTEN keeps it to the server, not to browsers or clients that happen to be connected to it. Without that filter the list also includes your browser, so you could end up quitting the browser instead of the server.
A range of ports works too, for example every port from 3000 to 3010:
lsof -ti tcp:3000-3010 -sTCP:LISTEN | xargs killRather click than type? Portlivo shows every port with its project and frees it in one click. Try it free for 7 days →
Step by step
- List what listens on the port:
lsof -nP -iTCP:3000 -sTCP:LISTEN - Check it is the right thing:
ps -p <PID> -o command= - Ask it to quit:
kill <PID> - Wait a moment and check again. Only if it is still running:
kill -9 <PID>
Not sure how to read the lsof output? The port-in-use guide walks through each column.
kill, kill -INT or kill -9?
| Command | Signal | When to use it |
|---|---|---|
kill <PID> | SIGTERM | First choice. The server closes files and connections, then exits. |
kill -INT <PID> | SIGINT | What Ctrl-C sends. Useful when a server only cleans up on Ctrl-C. |
kill -9 <PID> | SIGKILL | Last resort. It can’t be caught, so nothing gets cleaned up. |
Shortcuts if you do this often
Add a function to ~/.zshrc, open a new terminal, then run killport 3000:
killport() { lsof -ti tcp:"$1" -sTCP:LISTEN | xargs kill; }Or use an npm tool. npx kill-port 3000 sends SIGKILL right away, with no grace period. npx fkill-cli :3000 stops the process on a port, and npx fkill-cli on its own opens an interactive picker.
Stop a server by name instead of port
When you know what it is but not which port it took, match the command line with pkill -f:
pgrep -lf "vite" # list matching processes first
pkill -f "vite" # then stop them (SIGTERM)-f matches anywhere in the full command line, so pkill -f node stops every Node process, your editor’s helpers included. Always run pgrep -lf with the same pattern first and check the list.
Check the port is free
nc -z localhost 3000 2>/dev/null && echo taken || echo freefree means you can start your server. If it still says taken a second after you stopped the process, a supervisor restarted it: see the next section.
When it comes straight back
A supervisor is restarting it. Stop it at the source:
| What holds the port | Stop it with |
|---|---|
| Homebrew service (Postgres, MySQL, Redis) | brew services stop <name> |
| Docker or OrbStack container | docker stop <container> |
| pm2 | pm2 stop <name> |
| nodemon or a file watcher | Ctrl-C in the terminal that runs it |
| launchd agent | launchctl bootout gui/$(id -u)/<label> |
| Laravel Herd (nginx, PHP, dnsmasq) | Stop it from Herd |
To find a launchd agent’s label, look in ~/Library/LaunchAgents or run launchctl list | grep <name>.
“Operation not permitted”
The process belongs to another user or to root. You can stop it with sudo kill <PID>, but check what it is first: system services usually listen on a port for a reason. One to leave alone: ControlCe on 5000 or 7000 is AirPlay Receiver, which you turn off in System Settings instead.
The one-click way: Portlivo
In Portlivo, select the port and press K (or ⌘⌫). It re-checks that the PID still belongs to the same server, sends SIGTERM first, and routes Homebrew services and Docker containers through brew services and docker stop. Root-owned processes are left alone.
From Terminal, the devports command does the same: devports kill 3000.
Try Portlivo free for 7 days. Every feature, no account.
Download for MacStill have a question?
Write to us — a real developer reads every email and replies personally.