lsof for ports on macOS
lsof (“list open files”) ships with macOS and is the quickest way to see which process has a port. It needs the right flags to give you a straight answer.
The command
lsof -nP -iTCP:3000 -sTCP:LISTEN | Flag | What it does |
|---|---|
-iTCP:3000 | Only TCP sockets on port 3000 |
-sTCP:LISTEN | Only sockets in the LISTEN state: servers, not connections |
-n | Don’t look up hostnames (faster, and shows real addresses) |
-P | Don’t turn port numbers into service names |
-t | Print only PIDs, for use in scripts |
Why -P matters
Without it, lsof swaps port numbers for names from /etc/services. On a Mac, lsof -i :4321 showed a server as TCP *:rwhois (LISTEN); the same server with -nP showed TCP *:4321 (LISTEN). If you’re hunting for a port number, ask for numbers.
Why -sTCP:LISTEN matters
-i tcp:3000 matches any socket whose local or remote port is 3000, so a browser tab connected to your server shows up as well as the server. In our test, with one server and one connected client, plain lsof -ti tcp:PORT returned two PIDs and lsof -nP -iTCP:PORT -sTCP:LISTEN -t returned one. If you feed the result into kill, that difference matters.
Reading the result
The NAME column tells you where the server is listening. *:3000 means every address; 127.0.0.1:3000 or [::1]:3000 means this Mac only, over IPv4 or IPv6. The same port can be held twice, once on each, by two different processes: we saw a Node app on [::1]:4321 and a Python server on *:4321 side by side. That’s also how “it’s running but I get the wrong app” happens.
Everything that’s listening
lsof -nP -iTCP -sTCP:LISTEN Drop the port to list every listening socket on the Mac. Expect some system processes in there: ControlCe on 5000 and 7000 is AirPlay Receiver, for example. To stop one of your own, see how to kill a process on a port on Mac.