“Port 3000 already in use” on Mac: how to fix it
Your dev server won’t start because something already listens on its port. Here’s the one-line fix, how to check what you’re stopping, and what to do when the port is taken again a second later.
By Anmol Sethi · Updated
Quick fix
To free port 3000 on a Mac, stop whatever is listening on it:
lsof -ti tcp:3000 -sTCP:LISTEN | xargs killChange 3000 to your port (5173 for Vite, 8000 for Django or Laravel), then start your server again. If nothing is listening, the command does nothing. Read on if you want to check what you’re stopping first, or if the port is taken again straight away.
Rather click than type? Portlivo shows every port with its project and frees it in one click. Try it free for 7 days →
The errors this fixes
Every framework words it differently, but they all mean the same thing:
Error: listen EADDRINUSE: address already in use :::3000(Node, Next.js, Express)Port 5173 is in use, trying another one...(Vite)Address already in use - bind(2) for "0.0.0.0" port 3000 (Errno::EADDRINUSE)(Rails, Puma)Error: That port is already in use.(Django)Failed to listen on 127.0.0.1:8000 (reason: Address already in use)(Laravelartisan serve)OSError: [Errno 48] Address already in use(Python, Flask)
Only one process can listen on a TCP port at a time, and another one got there first.
Find what is using the port
Ask macOS which process is listening, here on port 3000:
lsof -nP -iTCP:3000 -sTCP:LISTENYou get something like this:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 48213 you 23u IPv6 0x8c2f1a3e5b7d9f01 0t0 TCP *:3000 (LISTEN)- COMMAND is the program, so you’ll see
node,phporruby, not your project’s name. - PID is the number you pass to
kill. - NAME is the address.
*:3000accepts connections from your whole network;127.0.0.1:3000or[::1]:3000only from this Mac. - Two lines with the same PID (one IPv4, one IPv6) are one server. Stop it once.
To see the full command line and the folder it was started in, which is usually the project:
ps -p <PID> -o command=
lsof -a -p <PID> -d cwd -Fn | sed -n 's/^n//p'Stop it
Ask the process to quit politely first. Dev servers shut down cleanly on SIGTERM:
kill <PID>Only if it is still there after a few seconds, force it:
kill -9 <PID>From npm, npx kill-port 3000 does the same in one step, but it sends SIGKILL (kill -9) straight away, so the server gets no chance to clean up. More options in how to kill the process on a port.
If the process comes straight back, something supervises it. Stop Homebrew services with brew services stop <name> and containers with docker stop <name> instead of killing the process.
lsof shows nothing, but the port is still taken
- The process belongs to another user or to root. lsof only lists your own processes. Try
sudo lsof -nP -iTCP:3000 -sTCP:LISTEN. - Docker publishes the port. lsof shows
com.docker.backend(or OrbStack) rather than your app. Find the container withdocker ps --filter publish=3000and stop it withdocker stop <name>. - The old server only just exited. Wait a few seconds and start again.
Port 5000 or 7000: AirPlay Receiver
On recent macOS, AirPlay Receiver listens on ports 5000 and 7000, which clashes with Flask and some other tools. lsof shows it as ControlCe (ControlCenter, cut to nine characters). Don’t kill it: it comes straight back.
Turn off System Settings → General → AirDrop & Handoff → AirPlay Receiver, or run your app on another port, for example flask run --port 5001.
Why it keeps happening
On a Mac, the usual culprits are:
- A dev server from earlier is still running: the terminal tab was closed, the editor crashed, or it was started in the background.
- An AI coding agent (Claude Code, Codex) started a server and left it running.
- Another project uses the same default port, like two Next.js apps on 3000.
- A Docker container or a Homebrew service (Postgres on 5432, Redis on 6379) starts at login.
Or run on another port
If the other server should keep running, start yours somewhere else:
PORT=3001 npm run dev # Express and most Node servers
npx next dev -p 3001 # Next.js
npx vite --port 5174 --strictPort # Vite
php artisan serve --port=8001 # Laravel
bin/rails server -p 3001 # Rails
python manage.py runserver 8001 # Django
flask run --port 5001 # FlaskVite quietly moves to the next free port (5174, 5175…) when 5173 is taken, so you can end up running two copies of the same app. Set server.strictPort: true in vite.config to get an error instead.
To make the port stick, set it in the project: "dev": "next dev -p 3001" in package.json, or server: { port: 5174 } in vite.config.
The one-click way: Portlivo
Portlivo shows every listening port with its project folder and command, so you can see at a glance what holds 3000. When a server fails because its port is taken, a notification offers Kill Holder & Retry: it stops whatever holds the port and starts your command again.
It re-checks the PID before stopping anything, and stops Homebrew services and Docker containers through their own managers, so they don’t respawn.
Try Portlivo free for 7 days. Every feature, no account.
Download for MacStill have a question?
Write to us — a real developer reads every email and replies personally.