Free the Port: Diagnose and Kill Local Listeners (whoport)
When port 3000 is 'already in use', here’s the fast way to identify and free it on macOS, Linux, or Windows.
8/18/2025 • 2 min
Scenario: port 3000 is busy. I need it now. This is the fastest way to see who owns it and free it.
TL;DR
-
See who owns the port:
./whoport 3000
(Shows IPv4/IPv6 bind status and any listener PIDs/process names.)
-
Free it (carefully):
./whoport 3000 --kill # TERM → KILL on macOS/Linux, taskkill /F on Windows
-
No whoport? Quick one-liner (macOS/Linux):
for p in $(lsof -nP -iTCP:3000 -sTCP:LISTEN -t); do kill -15 "$p"; done sleep 1 for p in $(lsof -nP -iTCP:3000 -sTCP:LISTEN -t); do kill -9 "$p"; done
Why ports “randomly” collide
- a leftover dev server (next/vite/etc.) still listening in another tab.
- an ipv6-only listener (
::1
or[::]
) blocks the port even when ipv4 looks free. - bound to a different interface (
0.0.0.0
vs127.0.0.1
). - a docker container publishing the port.
- rarely: the app is udp or not yet in LISTEN.
this playbook checks both ipv4 and ipv6, shows the owning process, and offers safe kill options.
Install the helper (whoport)
whoport
is a tiny, single-file python CLI that answers “who’s on this port?”
# in your scripts folder
chmod +x whoport.py
mv whoport.py whoport # optional rename
./whoport 3000
Example output
PORT 3000
IPv4 127.0.0.1 bind: FAIL [Address already in use]
IPv6 ::1 bind: FAIL [Address already in use]
LISTENERS
- pid 12345 proc node addr 127.0.0.1:3000
Freeing the port
Using whoport
./whoport 3000 --kill # may need sudo on macOS/Linux
./whoport 3000 # re-check; expect both IPv4+IPv6 bind OK
Without whoport (macOS/Linux)
lsof -nP -iTCP:3000 -sTCP:LISTEN # see owners
for p in $(lsof -nP -iTCP:3000 -sTCP:LISTEN -t); do kill -15 "$p"; done
sleep 1
for p in $(lsof -nP -iTCP:3000 -sTCP:LISTEN -t); do kill -9 "$p"; done
Windows (PowerShell/CMD)
netstat -ano | findstr :3000
taskkill /PID <PID> /F
Docker checks (optional)
docker ps --format '{{.ID}}\t{{.Ports}}\t{{.Names}}' | grep ':3000->' || true
# If found:
docker kill <container_id>
IPv6 gotchas
if whoport
shows ipv4 free but ipv6 blocked, your app may try ipv6 first. either:
- bind explicitly to ipv4:
--host 127.0.0.1
, or - free the ipv6 listener (often another dev server bound to
[::]
or::1
).
Make it muscle-memory
add a shell alias:
alias killport='f(){ for p in $(lsof -nP -iTCP:$1 -sTCP:LISTEN -t); do kill -15 "$p"; done; sleep 1; for p in $(lsof -nP -iTCP:$1 -sTCP:LISTEN -t); do kill -9 $p; done; }; f'
# usage: killport 3000