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:3000limits the output to TCP port 3000, and-sTCP:LISTENkeeps only the process that owns the port. Without it,lsofalso lists everything connected to that port, such as the browser tab showing your app.-nand-Pprint raw addresses and port numbers instead of looking up names, which is faster and avoids:hbcishowing up where you expected:3000.COMMANDis shortened to the executable name, so it often just saysnodeorPython. 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 -9matches every process with a connection on port 3000, not just the server. That can include your browser. Keep-sTCP:LISTENin it and drop-9:lsof -ti tcp:3000 -sTCP:LISTEN | xargs kill.killall nodeorpkill nodestops every Node.js process you own: other projects' dev servers, editor extensions, and command-line tools built on Node.pkill -f somethingmatches 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 forbunalso 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.
lsofonly 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 psand stop it withdocker stop <container>. - It's UDP, not TCP. Use
lsof -nP -iUDP:3000.