Skip to content
AppVerz

Blog / 9 November 2026

Port 3000 is already in use on a Mac: find it, stop it, and keep it stopped

The exact commands to find what is holding a port and stop it, why the process sometimes comes straight back, what is really on port 5000, and how to see every port on your Mac at once.

By AppVerz4 min read
Stackyard's Localhost section: listening ports with green and blue health dots and container names, and the detail for localhost:3000 showing HTTP 200, the Docker container, PID, uptime, memory, who started it, and Open, Copy URL, Show in Finder, Stop and Share on LAN buttons.
Error: listen EADDRINUSE: address already in use :::3000

Something on your Mac already owns that port. Here is how to find it and how to stop it, in about thirty seconds.

The fix

Ask which process is listening:

lsof -nP -iTCP:3000 -sTCP:LISTEN

-nP skips name lookups, so it answers immediately, and -sTCP:LISTEN limits the output to the process that owns the port, leaving out anything merely connected to it. You will get something like this:

COMMAND   PID   USER   FD   TYPE  DEVICE  SIZE/OFF  NODE  NAME
node    48213   you    23u  IPv6  0x...   0t0       TCP   *:3000 (LISTEN)

Stop it, using the number from the PID column:

kill 48213

Give it a couple of seconds and rerun your server. If the process is still there, kill -9 48213 ends it without letting it clean up. Keep that one for last.

If it came straight back

You killed it, and a moment later the port is taken again with a new PID. Something is restarting it. In rough order of likelihood:

A file watcher or a parent process. nodemon, a turbo task or a parent shell script. Find the parent, and stop that instead:

ps -o ppid=,command= -p 48213

A process manager. If you have ever used pm2 on this machine, check pm2 list, then pm2 delete <name>.

Docker. If COMMAND shows com.docker.backend, the process is Docker's port forwarder and killing it is the wrong move. Find the container instead:

docker ps --filter publish=3000
docker stop <name>

A container with a restart policy will return next time Docker starts. If it belongs to a Compose project, docker compose down in that folder is the tidy way to stop it.

A Homebrew service. Common on database ports like 5432 and 6379. brew services list shows what is running and brew services stop <name> stops it from coming back at login.

A launch agent. Something you installed long ago may be registered to restart whenever it exits. launchctl list | grep -i <name> will find it.

Port 5000 is a special case

If you run Flask or anything else on port 5000 and lsof names ControlCenter, it is not one of yours. Since macOS Monterey, AirPlay Receiver has listened on ports 5000 and 7000.

Do not kill it. Either turn off AirPlay Receiver in System Settings › General › AirDrop & Handoff, or run your app elsewhere, for example flask run -p 5001. If it is a container, map a different host port with -p 5001:5000.

What the terminal does not tell you

That all works, and it answers one question about one port. The trouble is that the port clash is usually a symptom. You have a server from yesterday still running, in a tab you closed, and it is probably not the only one.

Stackyard is a menu-bar app for Mac developers, and its Localhost section (⌘4) lists every server listening on your Mac at once, each with a health dot: green for an HTTP server answering normally, red for a 5xx or no answer, blue for something that is not a web server, like Postgres or Redis.

For the situations above, that means:

  • Who owns the port is the row itself. Ports opened by Docker show the container's name rather than com.docker.backend, which removes a whole step.
  • Who started it is in the detail pane. A server left by VS Code, Cursor, Claude Code or a terminal tab says so, along with its PID, uptime and memory.
  • Stopping it is a button. So are Open, Copy URL and Show in Finder.
  • AirPlay's ports are hidden unless you press Show System Ports, so your list stays to the things that are yours.
  • Homebrew services have on/off switches in the Docker section, with no need to recall the exact service name.

There is also the leftover problem. Orphans in the Memory section lists node and python processes whose terminal or editor has gone, and shows which tool left each one. That post goes through it. Guard can quit them for you after 15 minutes, 30 minutes or an hour, leaving databases and services like Postgres and Redis alone.

Preventing the clash next time

Add the folders where you keep code to Stackyard's Projects and it finds your dev and start scripts. Start a project from there, and if the port it needs is taken, Stackyard warns you before it starts, instead of leaving you to read a stack trace. Projects started from Stackyard also stop when you quit Stackyard, so they do not outlive the session.

If you only hit this once a month, the lsof line above is all you need, and you are welcome to it. If you hit it weekly, Stackyard is free for three days, then from $21 once, with no subscription. Download it from its page.

Questions people ask

How do I see what is using a port on a Mac?
Run lsof -nP -iTCP:3000 -sTCP:LISTEN in Terminal, replacing 3000 with your port. The COMMAND and PID columns tell you the process and its ID.
Why is port 5000 in use when I have not started anything?
On macOS Monterey and later, AirPlay Receiver listens on ports 5000 and 7000. lsof shows the owner as ControlCenter. Turn off AirPlay Receiver in System Settings › General › AirDrop & Handoff, or use a different port.
Should I use kill -9?
Only after a plain kill has failed. A plain kill lets the process shut down cleanly, which matters for anything holding a database or writing files. kill -9 ends it immediately with no chance to clean up.

Related reading

Have a question about any of this?

Write in. The person who built the apps reads every message and replies within two working days.