Guide

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 kill

Rather 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

  1. List what listens on the port: lsof -nP -iTCP:3000 -sTCP:LISTEN
  2. Check it is the right thing: ps -p <PID> -o command=
  3. Ask it to quit: kill <PID>
  4. 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?

CommandSignalWhen to use it
kill <PID>SIGTERMFirst choice. The server closes files and connections, then exits.
kill -INT <PID>SIGINTWhat Ctrl-C sends. Useful when a server only cleans up on Ctrl-C.
kill -9 <PID>SIGKILLLast 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 free

free 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 portStop it with
Homebrew service (Postgres, MySQL, Redis)brew services stop <name>
Docker or OrbStack containerdocker stop <container>
pm2pm2 stop <name>
nodemon or a file watcherCtrl-C in the terminal that runs it
launchd agentlaunchctl 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 Mac

Still have a question?

Write to us — a real developer reads every email and replies personally.

support@portlivo.com