DevPorts$9 · Buy

How to find and kill the process using a port on a Mac

Updated · Tested on macOS 27

“Port 3000 is already in use” means another process is listening on it, usually a dev server you forgot about. Find it with lsof, check it's the one you expect, and stop it with kill. Replace 3000 with your port.

The short answer

lsof -nP -iTCP:3000 -sTCP:LISTEN
kill <PID>

The first command shows the process listening on port 3000. The second asks it to shut down cleanly. Run the first command again: if it prints nothing, the port is free.

1. Find what is listening on the port

$ lsof -nP -iTCP:3000 -sTCP:LISTEN
COMMAND   PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
node    41822  you   23u  IPv6  0x...       0t0  TCP *:3000 (LISTEN)
  • -iTCP:3000 limits the output to TCP port 3000, and -sTCP:LISTEN keeps only the process that owns the port. Without it, lsof also lists everything connected to that port, such as the browser tab showing your app.
  • -n and -P print raw addresses and port numbers instead of looking up names, which is faster and avoids:hbci showing up where you expected :3000.
  • COMMAND is shortened to the executable name, so it often just says node or Python. The PID is what identifies the exact process.

Before stopping it, check which project it belongs to and how it was started:

ps -o pid,ppid,etime,command -p <PID>
lsof -a -d cwd -p <PID>

The first shows the full command and how long it has been running. The second shows its working directory, which is usually the project folder.

2. Stop it

kill <PID>

kill sends SIGTERM, which lets the server close connections, flush files, and stop its child processes. Most dev servers exit within a second or two. Only if it is still listening after a few seconds, force it:

kill -9 <PID>

SIGKILL ends the process immediately with no cleanup. Child processes it started, like a bundler worker or a database, can be left running on their own, so check the port and ps again afterwards.

One-liners to avoid

  • lsof -ti :3000 | xargs kill -9 matches every process with a connection on port 3000, not just the server. That can include your browser. Keep -sTCP:LISTEN in it and drop -9: lsof -ti tcp:3000 -sTCP:LISTEN | xargs kill.
  • killall node or pkill node stops every Node.js process you own: other projects' dev servers, editor extensions, and command-line tools built on Node.
  • pkill -f something matches anywhere in the full command line, so a short pattern hits unrelated processes. Matching names is fragile in general: while testing this guide, a filter for bun also matched a system process whose path contains .bundle. Stop processes by PID after checking what they are.

The port is taken again right after you kill it

Something restarted the server. Common causes are a file watcher like nodemon, a parent task runner such as pnpm dev or turbo, or a process manager like pm2. Look at the parent process and stop that instead:

ps -o pid,ppid,command -p <PID>     # note the PPID
ps -o pid,command -p <PPID>

If the parent is your shell (zsh or bash), don't kill it; that closes the terminal session. Stop the dev command in that terminal with Ctrl-C instead. For pm2, use pm2 stop; for Homebrew services, use brew services stop.

“Address already in use” but lsof shows nothing

  • Another user or root owns it. lsof only shows your own processes without elevated rights: sudo lsof -nP -iTCP:3000 -sTCP:LISTEN.
  • Port 5000 or 7000. macOS's AirPlay Receiver listens on both. Turn it off in System Settings → General → AirDrop & Handoff, or run your server on another port.
  • A container publishes the port. With Docker Desktop or OrbStack, the listener is the container runtime rather than your app. Find the container with docker ps and stop it with docker stop <container>.
  • It's UDP, not TCP. Use lsof -nP -iUDP:3000.