Tutorial 6 min read

How to Kill a Port on Mac (5 Ways That Actually Work in 2026)

"Port 3000 already in use" is the most common Mac dev annoyance. Here are five ways to fix it — one-line shortcut, Activity Monitor, and a launcher trick that skips Terminal entirely.

How to kill a port on Mac with Terminal lsof and kill commands
TL;DR — The fastest fix

Open Terminal and run:

lsof -ti:3000 | xargs kill -9

Replace 3000 with the port you want to free. This finds the process listening on that port and force-kills it. The port is immediately available again.

The 5 methods at a glance

Method Speed Best for
1. lsof + xargs one-liner2 secondsDaily dev use
2. Find PID, then kill -95 secondsWhen you want to see what is running
3. killall by name3 secondsKilling all Node, Python, Java processes
4. Activity Monitor (GUI)15 secondsNon-Terminal users
5. Brow launcher: type kill 30001 secondForgetting lsof syntax forever

Method 1: The lsof one-liner (the dev favorite)

This is the command you should put in a shell alias. It frees a port in one step:

lsof -ti:3000 | xargs kill -9

Breaking it down:

  • lsof — macOS utility that lists open files (and on Mac, network sockets are files).
  • -t — output only the process ID (no header, no extra columns). This makes the result pipeable.
  • -i:3000 — filter to the network connection bound to port 3000.
  • | xargs — take the PID from stdin and pass it as an argument.
  • kill -9 — send SIGKILL to that PID. The kernel enforces it; the process cannot trap or ignore it.

Pro tip: drop this in your ~/.zshrc as an alias so you never type it again:

killport() {
  lsof -ti:$1 | xargs kill -9
}

Then just run killport 3000 any time a port gets stuck.

Method 2: Find the PID, then kill it

If you want to see what is actually running on the port before you kill it (for example, to confirm it is your dev server and not something important), use the two-step version:

lsof -i :3000

Output looks like this:

COMMAND   PID  USER   FD   TYPE  NAME
node    51234  you   23u   IPv4  TCP *:hbci (LISTEN)

Now kill it explicitly:

kill -9 51234

The flag matters. kill 51234 sends SIGTERM (signal 15), which is a polite "please shut down" message that some processes catch and ignore. kill -9 51234 sends SIGKILL (signal 9), which the kernel enforces immediately and the process cannot trap.

If kill returns Operation not permitted, the process belongs to another user (often root, if you started it with sudo). Prepend sudo:

sudo kill -9 51234

Method 3: killall by process name

Sometimes the issue is not one stuck Node server, it is fifteen of them, all spawned by a runaway nodemon or a debugger crash. Killing them by port one at a time is tedious. Kill them all by name:

killall node

Common variants developers use daily:

  • killall node — nukes every Node.js process. Useful when npm run dev has spawned children that survived a Ctrl-C.
  • killall python or killall python3 — same thing for Python servers.
  • killall -9 java — force-kill Java processes (some refuse SIGTERM).
  • killall ruby — useful for Rails servers.

Warning: killall node kills every Node process, including Electron apps you have running (VS Code, Slack, Discord, Figma). Use with care on a busy machine.

Method 4: Activity Monitor (the GUI option)

Not everyone wants to live in Terminal. If you prefer a graphical option:

  1. Open Activity Monitor (Cmd-Space, type "Activity").
  2. In the search box at the top right, type node (or python, java, whatever your dev server is).
  3. Click the Memory column to sort by usage — the runaway process is usually the highest.
  4. Select the process, click the X button in the toolbar, and choose Force Quit.

This is slower than the Terminal methods, and it does not let you target by port directly. But it works without remembering any commands and gives you a visual of what is actually running.

Method 5: Brow launcher (skip Terminal entirely)

If you find yourself typing lsof -ti:3000 | xargs kill -9 three times a day and wishing it were faster, here is a fix: Brow's launcher has a port killer built in. Press Option + Space, type kill 3000, hit return.

That is it. No Terminal, no remembering syntax, no shell alias to maintain. The launcher runs the same lsof + kill pipeline under the hood, but you never see it.

The launcher also has the rest of the dev shortcuts you forget five times a week: UUID generation, Base64 encoding, Unix timestamp conversion, JSON formatting, hashing (MD5/SHA-256), case conversion (camelCase, snake_case, kebab-case, CONSTANT_CASE), and a Mac-wide GIF picker. See the full launcher feature list.

Download Brow free →

Common Mac dev ports cheat sheet

Port Default for Quick kill
3000Node.js, Express, Next.js, Create React Applsof -ti:3000 | xargs kill -9
3001Storybook, secondary Node serverslsof -ti:3001 | xargs kill -9
4200Angular CLIlsof -ti:4200 | xargs kill -9
5000Flask, AirPlay receiver (macOS!)lsof -ti:5000 | xargs kill -9
5173Vite dev serverlsof -ti:5173 | xargs kill -9
8000Django, Python http.serverlsof -ti:8000 | xargs kill -9
8080Tomcat, Spring Boot, generic HTTP altlsof -ti:8080 | xargs kill -9
8888Jupyter Notebooklsof -ti:8888 | xargs kill -9
9000PHP-FPM, SonarQube, Webpack dev serverlsof -ti:9000 | xargs kill -9

Heads up about port 5000 on macOS: Apple uses port 5000 for AirPlay Receiver. If you cannot bind to 5000 even after killing your Flask app, the issue might be macOS itself. Disable it in System Settings → General → AirDrop & Handoff → AirPlay Receiver.

Why "port already in use" keeps happening

Most of the time, the cause is one of four things:

  • You closed the terminal without stopping the dev server. The process becomes orphaned and keeps holding the port.
  • Your IDE crashed mid-debug. The debug adapter spawned a child process that survived the IDE crash.
  • Hot reload spawned children that did not get cleaned up. Common with nodemon, tsx watch, and Webpack dev server before v5.
  • A Docker container is bound to the port and you forgot. Run docker ps to check before you kill anything.

How to prevent it

You cannot eliminate this entirely — it is a fact of dev life — but you can reduce how often it happens:

  • Use a process manager. Tools like PM2 or overmind handle child cleanup correctly.
  • Trap signals in your dev script. If you wrap your server in a script, register handlers for SIGINT and SIGTERM that close the server before exiting.
  • Set --kill-others-on-fail when using concurrently to run multiple processes — if one crashes, the others get killed too.
  • Add the killport alias above — you cannot prevent it, but you can make recovery cost two seconds instead of thirty.

Bonus: kill all dev processes at once

End-of-day cleanup. Save this in your shell rc and call it before you close the laptop:

cleanup_dev() {
  for port in 3000 3001 4200 5000 5173 8000 8080 8888 9000; do
    lsof -ti:$port 2>/dev/null | xargs -r kill -9 2>/dev/null
  done
  echo "All dev ports freed"
}

Run cleanup_dev and every common dev port is free.

Frequently Asked Questions

How do I kill port 3000 on Mac?

Run this command in Terminal: lsof -ti:3000 | xargs kill -9. The lsof -ti flag returns just the process ID listening on port 3000, and xargs kill -9 sends a SIGKILL signal to terminate it. The port is freed immediately.

Why does kill PID not work sometimes on Mac?

kill PID without a flag sends SIGTERM (signal 15), which asks the process to shut down cleanly. Some processes ignore or trap SIGTERM. Use kill -9 PID to send SIGKILL, which the kernel enforces and the process cannot ignore. SIGKILL is what you want when a port is stuck.

Do I need sudo to kill a process on Mac?

Only if the process was started by root or another user. If you started the dev server yourself, you can kill it without sudo. If you see Operation not permitted, retry the same command with sudo prepended: sudo kill -9 PID.

What does lsof -i :3000 do on Mac?

lsof stands for list open files. The -i :3000 flag filters to network connections on port 3000. It prints a table with the command name, PID, user, and connection state. Add -t to get just the PID, useful for piping to kill.

Why does "port already in use" keep happening on Mac?

It usually means a previous process did not exit cleanly. Common causes: closing the terminal without stopping the dev server (the process gets orphaned), nodemon respawns leaving zombie processes, Docker containers binding ports without cleanup, and crashed IDE debug sessions. Killing the port is a fix; preventing it requires trapping signals in your dev script or using a process manager.

Does fuser work on Mac for killing ports?

No. fuser is a Linux utility and does not ship with macOS. Use lsof on Mac instead. If you migrated from Linux and want fuser-like behavior, the equivalent is lsof -ti:PORT | xargs kill -9.

Stop typing lsof -ti:3000 | xargs kill -9

Type kill 3000 in Brow's launcher instead. Plus 30+ other dev shortcuts.

Download Brow Free macOS 13+ · No account needed · No credit card · 20MB · brew install --cask brow