Purpose: Find and kill the process on a TCP port. · Lang: POSIX sh · Deps:
lsof+kill(macOS) Copy to: your project orbin. · Use when: a dev server is stuck on a port; not Linux — usefuser/ssthere.
Find and (optionally) kill whatever is listening on a TCP port — the usual fix for "address already in use" after a dev server didn't shut down cleanly.
Built on lsof + kill, both built into macOS. Zero runtime dependency to
install.
The default is deliberately safe: kill-port <port> reports what is
listening and kills nothing. You have to opt in with -f/--force to send a
signal. This avoids the muscle-memory accident of nuking the wrong process when
you fat-finger a port.
kill-port [-f|--force] [-9|--kill] <port>
-f, --force actually send the signal (default: report only)
-9, --kill SIGKILL instead of the default SIGTERM
-h, --help show help
- SIGTERM by default (graceful);
-9/--killupgrades to SIGKILL. - Multiple PIDs on the same port are all handled — each is signalled and reported individually.
-9still requires--forceto act; on its own it only changes which signal a forced run would send.
| Code | Meaning |
|---|---|
0 |
killed, or reported successfully with something listening |
1 |
bad usage / invalid port |
3 |
nothing was listening on that port |
"Nothing listening" is a distinct 3 (not an error 1) so a wrapper script can
tell "already free" apart from "you called me wrong" — while still being
non-zero so kill-port X && start X won't barrel ahead on a typo. Flip it to
exit 0 if you'd rather treat an empty port as success.
kill-port 3000 # show what's on :3000, kill nothing
kill-port -f 3000 # SIGTERM the listener(s) on :3000
kill-port -f -9 3000 # SIGKILL the listener(s) on :3000Example session:
$ kill-port 3000
Listening on TCP port 3000:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 47143 laurie 3u IPv4 0x... 0t0 TCP *:3000 (LISTEN)
Reported only. Re-run with -f/--force to send SIGTERM.
$ kill-port -f 3000
Listening on TCP port 3000:
...
Sent SIGTERM to PID 47143 (node)
mkdir -p ~/.local/bin
cp kill-port.sh ~/.local/bin/kill-port
chmod +x ~/.local/bin/kill-port
# ensure ~/.local/bin is on your PATH (add to ~/.zshrc if needed):
# export PATH="$HOME/.local/bin:$PATH"Or just run it in place: ./kill-port.sh 3000.
- Always-kill (skip the report-only gate): drop the
forceflag and theif [ "$force" -eq 0 ]block — but then you lose the safety net. - Confirm instead of
--force: swap the gate for areadprompt (printf 'kill these? [y/N] '; read ans). The--forceflag was chosen over a prompt so the script stays usable non-interactively (in apackage.jsonscript, a Makefile, etc.). - UDP too: change
-iTCP:to-iUDP:(UDP has noLISTENstate, so drop the-sTCP:LISTENfilter for that case).
The lsof flags here (-nP -iTCP:<port> -sTCP:LISTEN -t) are macOS-oriented and
work with Linux lsof too, so the script is portable as-is. If you'd rather use
native Linux tooling:
fuser -k <port>/tcp # find and kill in one shot (add -k to kill)
ss -ltnp | grep :<port> # inspect the listener and its PIDfuser -k is the closest one-liner, but note it kills immediately with no
report-first step.