Port 3000 Already in Use on Mac: How to Find and Free It
Getting EADDRINUSE on port 3000? Here's how to find what's holding the port and kill it, with or without Terminal.
You start your dev server and immediately see:
Error: listen EADDRINUSE: address already in use :::3000
Nothing else changed. You didn’t start another server. Yet something is holding port 3000 hostage.
Why This Happens
Port conflicts usually come from a process that crashed or was force-quit without releasing its socket. When a process exits uncleanly, the macOS kernel keeps the port bound until the process is fully gone or explicitly killed. The socket stays open even though nothing is actively listening on it.
This hits most often with Node.js servers, Rails applications, and other dev frameworks that default to port 3000. You close your terminal window, the process gets stuck in limbo, and the next time you try to start a fresh server it collides with the leftover binding.
Finding the Process
The lsof command (list open files) shows which process owns a port. Run this in Terminal:
lsof -i :3000
You’ll get output like this:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 8412 aaron 23u IPv6 0x1234abcd5678 0t0 TCP *:3000 (LISTEN)
Here’s what each column means:
- COMMAND: the executable name holding the port
- PID: the process ID you’ll use to kill it
- USER: the account running the process
- FD: the file descriptor (the
usuffix means read/write) - TYPE:
IPv4orIPv6 - NODE: the protocol (
TCPhere) - NAME: the port and its state (
LISTENmeans it’s actively bound)
The PID column is what you need for the next step.
Killing It
Once you have the PID, send it SIGKILL:
kill -9 8412
The -9 flag sends SIGKILL, which forces the process to exit immediately. Unlike SIGTERM (signal 15), SIGKILL cannot be caught or ignored by the process. It terminates without any cleanup, which is exactly what you want when a process is already stuck.
If you want to do it in one line without looking up the PID:
kill -9 $(lsof -ti :3000)
The -t flag tells lsof to output only the PID, with no column headers. That makes it safe to pipe directly into kill.
When lsof Shows Nothing
If lsof -i :3000 returns no output but you’re still getting EADDRINUSE, the port is probably in TIME_WAIT state. This is an OS-level cooldown period that happens after a socket closes normally. The kernel holds onto the port for a short window (typically around 30 seconds on macOS) to handle any late-arriving packets from previous connections.
There is nothing to kill in this case because there is no process. Wait a minute and try again, or point your server at a different port temporarily while the cooldown clears.
Other Dev Ports
The same lsof and kill commands work for any port. Common ones developers run into:
- 5000: Python Flask, older Rails
- 8080: Java servlet containers, many proxies
- 8000: Django, Python HTTP servers
- 5173: Vite
- 4200: Angular CLI
Just swap the port number in lsof -i :PORT and kill -9 $(lsof -ti :PORT).
Using Portie
If you’d rather not memorize flags, Portie shows every open port on your Mac with its owning process, refreshed automatically every 3 seconds. The live list is free. You can see at a glance what’s bound to port 3000 and which app owns it.
The $8.99 one-time unlock adds the ability to kill a process directly from the list, with either SIGTERM or SIGKILL, without opening Terminal. If you spend any time in local development, the two-second kill-from-list workflow pays for itself quickly.