Port already in use on macOS
You start a dev server and get EADDRINUSE, or address already in use, or just a server that quietly refuses to boot. Something is already listening on that port. Here is how to find out exactly what, decide whether it is safe to stop, and get moving again.
1. Find what is holding the port
macOS ships with lsof, which lists open files — and a listening socket is one of them.
lsof -nP -iTCP:3000 -sTCP:LISTENSwap 3000 for the port you care about. You will get a line like this:
COMMAND PID USER FD TYPE NAME
node 12345 danmarek 23u IPv4 127.0.0.1:3000 (LISTEN)The two columns that matter are COMMAND and PID. If the command prints nothing at all, nothing is listening on that port — your error is coming from somewhere else.
The flags are worth knowing, because most versions of this command you will find online omit them. -n skips reverse-DNS lookups and -P skips port-name lookups, which makes it fast and prints 127.0.0.1:3000 rather than localhost:http-alt. -sTCP:LISTEN is the important one: without it you also get every open connection to that port, which is usually a wall of noise rather than the one process you want.
2. Work out what it actually is
node tells you almost nothing when you have four projects and a couple of coding agents running. Ask for the full command line before you touch anything:
ps -o pid,ppid,command -p 12345That gives you the script and the working directory it was launched from, which is normally enough to recognise the project. If you want the whole picture at once, list every listening port on the machine:
lsof -nP -iTCP -sTCP:LISTEN3. Stop it — or take a different port
Taking a different port is usually the better move, because it keeps both servers running. Most tools accept one directly: PORT=3001 npm run dev, vite --port 5174, rails s -p 3001.
If you do want the port back, send a polite signal first:
kill 12345Plain kill sends SIGTERM, which asks the process to shut down and gives it a chance to flush what it has open. Only if it ignores that should you force it:
kill -9 12345-9 cannot be caught or ignored, so the process gets no opportunity to clean up. It is the last resort, not the default. In one step, if you are confident about what is there:
kill $(lsof -nP -iTCP:3000 -sTCP:LISTEN -t)-t prints just the PID, which is what makes it substitutable. If you get Operation not permitted, the process belongs to another user or to the system, and you should be quite sure before reaching for sudo.
Before you kill it: is it yours?
Not everything on a local port is a stray dev server. A few things worth recognising before you stop them:
- Databases. Postgres on 5432, Redis on 6379, MongoDB on 27017. Killing these mid-write is a bad afternoon.
- Docker. The listener is
com.docker.backend, not your app, so the PID you find is the wrong thing to kill. Find the container instead withdocker ps --filter publish=3000and stop that. - Ordinary Mac apps. Plenty of desktop software listens on a high local port for its own browser extension or helper. If the command name is an app you recognise, leave it alone and use another port.
- macOS itself. See below — ports 5000 and 7000 are the usual trap.
Port 5000 and 7000: it is AirPlay, not you
On macOS Monterey and later, AirPlay Receiver listens on ports 5000 and 7000. Flask defaults to 5000, so this surfaces constantly as a conflict with nothing of yours running — lsof points at ControlCenter, which looks alarming and is not something to kill. Either run your app on another port, or turn the receiver off in System Settings → General → AirDrop & Handoff → AirPlay Receiver.
Common ports and what usually holds them
| Port | Usually |
|---|---|
| 3000 | Next.js, Rails, Express, Create React App |
| 3001 | A second Next.js or Express app, often started by an agent |
| 4200 | Angular |
| 5000 | Flask — and macOS AirPlay Receiver, which is usually the real culprit |
| 5173 | Vite |
| 5432 | PostgreSQL |
| 6379 | Redis |
| 7000 | macOS AirPlay Receiver |
| 8000 | Django, Python http.server |
| 8080 | Tomcat, Spring Boot, proxies, a second web app |
| 27017 | MongoDB |
Why this keeps happening
The conflict is rarely the real problem — losing track is. Coding agents start servers and do not always stop them, worktrees each bring their own, and a week of that leaves a machine with a dozen listeners nobody remembers starting. The port you want is held by something you started on Tuesday.
The shortcut
TidyPorts is a free macOS menu bar app that does the above continuously: every listening port, what is on it, and — the part lsof cannot tell you — which agent, terminal and git branch it came from. It stops what is safe to stop and leaves databases, Docker and active stacks alone.
It answers the same question from the command line. You type the first line; the rest is what it prints back:
tidy-ports who 3000
:3000 is held by Claude Code, in Ghostty [PID 12345] in acme-web (feature/auth)
[1] use 3001 instead
[2] stop it (asks again first)
[enter] leave itTaking a different port comes first on purpose: it is the non-destructive option and keeps both servers running, which is usually what you want once the thing holding the port turns out to belong to someone — or something — else. Enter leaves it alone, so a stray keystroke never stops anyone’s server.
Piped into something rather than read by a person, it drops the prompt and prints the same answer as plain lines instead — which is what makes it usable by a coding agent that has just failed to bind and would otherwise guess.
Free, macOS 15 or later. Download it here, or carry on with lsof — it is on every Mac and it works.
Questions
How do I find what is using port 3000 on a Mac?
Run lsof -nP -iTCP:3000 -sTCP:LISTEN in Terminal. It prints the command name and PID of the process listening on that port. If it prints nothing, nothing is listening on that port.
Why does port 5000 say it is in use when nothing is running?
On macOS Monterey and later, AirPlay Receiver listens on ports 5000 and 7000. It is part of the operating system, not your project. Turn it off in System Settings under General, AirDrop & Handoff, or run your app on a different port.
Should I use kill -9?
Not first. Plain kill sends SIGTERM, which lets the process shut down cleanly and flush anything it has open. Use kill -9 only if the process ignores SIGTERM, because it gives the process no chance to clean up.
Is it safe to kill whatever is on the port?
Not always. Check the process name first. Stopping your own dev server is harmless, but the same port might be held by a database, a Docker container serving other work, or a normal Mac app that happens to use a high port.