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:LISTEN

Swap 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 12345

That 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:LISTEN

3. 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 12345

Plain 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 with docker ps --filter publish=3000 and 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

PortUsually
3000Next.js, Rails, Express, Create React App
3001A second Next.js or Express app, often started by an agent
4200Angular
5000Flask — and macOS AirPlay Receiver, which is usually the real culprit
5173Vite
5432PostgreSQL
6379Redis
7000macOS AirPlay Receiver
8000Django, Python http.server
8080Tomcat, Spring Boot, proxies, a second web app
27017MongoDB

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 it

Taking 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.