v1.0 — Now available for macOS · Press ⌘ Space to launch
← Back to blog

The lsof port cheatsheet for macOS developers

CmdSpace Team·

lsof is the standard tool for answering "what is using this port" on macOS. It is also one of the most cryptic command-line tools you will use this week. The man page is 300 lines of options, most of which you will never touch. This post i…

lsof is the standard tool for answering "what is using this port" on macOS. It is also one of the most cryptic command-line tools you will use this week. The man page is 300 lines of options, most of which you will never touch. This post is the cheatsheet — the 8 commands a working developer actually uses, with one-line explanations and the gotchas that bite first-time users.

If you find yourself looking up lsof syntax monthly, save this page.

The 8 commands you actually need

1. What is using port 3000?

lsof -i :3000

The most common invocation. Returns rows with COMMAND, PID, USER, FD, TYPE, DEVICE, SIZE/OFF, NODE, NAME. The PID column is what you want for kill.

2. Just the PID, nothing else

lsof -ti :3000

-t is "terse" — outputs only the PID. Useful for piping:

lsof -ti :3000 | xargs kill

The most common one-liner for "free up port 3000." See the Stack Overflow canonical answer for the full history.

3. All listening ports

lsof -i -P | grep LISTEN

-P shows numeric ports instead of service names (e.g. :3000 instead of :http). grep LISTEN filters out established connections. The result is the list of every process listening for incoming connections.

This is the "what is running on my machine" query.

4. All connections (not just listening)

lsof -i -P

Same as above but includes ESTABLISHED, TIME_WAIT, CLOSE_WAIT connections. Useful when debugging why a connection is hanging or why you have thousands of TIME_WAIT entries.

5. Listen on a specific port range

lsof -i :3000-3010

Lists everything on ports 3000 through 3010 inclusive. Useful when your dev environment uses sequential ports for multiple services.

6. Filter by IPv4 only

lsof -i4 -P | grep LISTEN

-i4 restricts to IPv4. The IPv6 noise (*:* placeholder rows) is one of the more confusing parts of default lsof output.

7. Connections to a specific host

lsof -i @localhost:3000

Reports only connections to localhost:3000. Useful when you want to confirm an outbound connection is happening (or not happening) to a specific destination.

8. By process name

lsof -i -P -c node

-c <name> filters by command name. Shows every port any node process is using. Useful when you have multiple Node services and want to see them all in one query.

The flags worth memorizing

FlagWhat it does
-iFilter to network sockets only
-PShow numeric ports (not service names)
-nShow numeric IPs (skip DNS lookup, much faster)
-tTerse output: PIDs only
-c <name>Filter by process command name
-u <user>Filter by user
-i :<port>Filter to a specific port
-i <proto>@<host>:<port>Full host/port filter

Combine them: lsof -nP -i :3000 -t is the "give me just the PID listening on port 3000, do not resolve DNS, do not look up service names" canonical fast query.

Common gotchas

IPv6 stub rows

Default lsof output includes rows like:

node    12345 you   23u  IPv6 0x...      0t0  TCP *:3000 (LISTEN)
node    12345 you   24u  IPv4 0x...      0t0  TCP *:3000 (LISTEN)

Same process, listening on both IPv4 and IPv6. Two rows is normal, not a bug.

Permission denied for system services

lsof -i :22
# returns nothing if you are not root

System services (sshd, mDNSResponder, etc.) only show up under sudo lsof. For your own dev processes you do not need sudo.

Slow first run

Default lsof resolves DNS for every connection. On macOS this can pause for several seconds. Add -n to skip:

lsof -nP -i :3000

Always faster than lsof -i :3000.

Stale entries during process startup

If you just started a service, there can be a fraction of a second where lsof sees the socket but not the process name. Add a small sleep before checking, or query twice.

"No such file or directory" warnings

lsof: WARNING: can't stat() ... file system

Means lsof is trying to walk a mount that requires permissions. Usually safe to ignore for port queries; add -w to suppress.

Piping patterns

The five lsof pipelines worth knowing:

Kill everything on a port

lsof -ti :3000 | xargs kill

Kill everything by a specific process name

pgrep -f my-service | xargs kill

(Not strictly lsof, but adjacent.)

Count established connections to a port

lsof -i :8080 | grep -c ESTABLISHED

Watch port use over time

watch -n 1 'lsof -i :3000'

(watch is not built-in on macOS by default; install via brew install watch.)

Save the listener list to a file

lsof -i -P -n | grep LISTEN > listeners-$(date +%s).txt

Why lsof exists in the first place

A short historical note. lsof ("list open files") predates the modern Linux ss command and was designed to be portable across BSD-derived Unixes. On Linux, ss -tulpn is the modern replacement and is faster for the listening-ports query. macOS does not ship ss, so lsof remains the canonical answer on this platform.

You will see netstat recommended in old posts. macOS's netstat exists but does not include the PID column you need for the kill workflow, which is why lsof won the developer-tool argument.

When lsof is not the answer

Three cases where lsof is the wrong tool:

  1. Docker container ports. lsof sees the host-side bind, not the container process. Use docker ps to see container ports.
  2. Containerized macOS services (rare). Some virtualized environments hide their sockets.
  3. Kernel-level listeners. Some Apple system services bind ports without exposing them in lsof. Add sudo if a port appears used but lsof shows nothing.

For 99% of "free port 3000" cases, plain lsof is the right tool.

A launcher-integrated alternative

If you want the kill-by-port flow without typing lsof syntax, install a launcher with a built-in command. CmdSpace has kill-by-port built in; Raycast has a community extension; Alfred has workflows. The interaction is "press hotkey, type port number." Under the hood it is the same lsof -ti :port | xargs kill.

Kill process by port on macOS covers the full ranking of methods. What is using port 3000 on my Mac covers the diagnostic side specifically.

The bottom line

Memorize three commands and you cover 95% of lsof use:

lsof -i :3000              # what is using port 3000
lsof -ti :3000 | xargs kill  # free port 3000
lsof -i -P | grep LISTEN   # everything listening

Everything else on this page is reference for the 5% of cases the three commands do not cover.


Sources