DEV Community

Cover image for How to kill the process on a port on a Mac (and what to do when it comes back)
Anmol Sethi
Anmol Sethi

Posted on Originally published at portlivo.com

How to kill the process on a port on a Mac (and what to do when it comes back)

You kill whatever is on port 5432, run your app, and get the same error. The process is back with a new PID. Most guides stop at kill -9, which is the wrong fix for this. Here's the full routine, in the order I use it.

The one-liner

Find the process listening on the port and ask it to quit:

lsof -ti tcp:3000 -sTCP:LISTEN | xargs kill
Enter fullscreen mode Exit fullscreen mode

-t prints only PIDs. -sTCP:LISTEN is the part most snippets leave out, and it matters: without it, lsof also returns every client connected to the port. If you have the app open in a browser, that includes the browser, and you quit it instead of the server.

A range of ports works too:

lsof -ti tcp:3000-3010 -sTCP:LISTEN | xargs kill
Enter fullscreen mode Exit fullscreen mode

The careful version

When you're not sure what's on the port, take it in four steps:

  1. See what's listening: lsof -nP -iTCP:3000 -sTCP:LISTEN
  2. Check it's the right thing: ps -p <PID> -o command=
  3. Ask it to quit: kill <PID>
  4. Check again after a second. Only if it's still there: kill -9 <PID>

Step 2 is the one people skip. node on port 3000 could be your app, or a different project you forgot was running.

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. Some servers only clean up on this one.
kill -9 <PID> SIGKILL Last resort. It can't be caught, so nothing gets cleaned up.

A database killed with -9 has to recover on its next start, and a dev server may leave a lock or socket file behind. Give SIGTERM a second before reaching for it.

Make it a command

If you do this every day, add a function to ~/.zshrc, open a new terminal, and run killport 3000:

killport() { lsof -ti tcp:"$1" -sTCP:LISTEN | xargs kill; }
Enter fullscreen mode Exit fullscreen mode

There are npm tools too. npx kill-port 3000 sends SIGKILL straight 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.

If you do this several times a day: full disclosure, I built Portlivo, a Mac menu bar app that lists every dev server and port. Select one and press K, and it stops it safely, including Homebrew services and Docker containers. It's $8.99 once (early-bird) after a 7-day free trial.

Stop it by name instead

When you know what it is but not which port it took:

pgrep -lf "vite"    # list matches first
pkill -f "vite"     # then stop them
Enter fullscreen mode Exit fullscreen mode

-f matches anywhere in the command line, so pkill -f node also stops your editor's helpers. Always run pgrep -lf with the same pattern first.

Check the port is free

nc -z localhost 3000 2>/dev/null && echo taken || echo free
Enter fullscreen mode Exit fullscreen mode

If it still says taken a second after you stopped the process, something restarted it.

When it comes straight back

That's a supervisor doing its job. Homebrew services run under launchd with KeepAlive, so a killed Postgres is restarted within a second. Killing it harder doesn't help. Stop it where it's managed:

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

Not sure which one it is? brew services list and docker ps cover most cases. For other launchd agents, look in ~/Library/LaunchAgents or run launchctl list | grep <name>.

"Operation not permitted"

The process belongs to root or another user. sudo kill <PID> works, but check what it is first. One to leave alone: ControlCe on port 5000 or 7000 is macOS's AirPlay Receiver. Turn it off in System Settings → General → AirDrop & Handoff instead.

That covers every way I free a port. If it saved you a trip to Stack Overflow, follow me for more Mac developer fixes like this one.

Top comments (0)