How to Check Open Ports on Mac: lsof, netstat, and nc
Check open ports on Mac using lsof -i :3000, netstat, and nc. Covers local port checking and testing remote hosts, with real command output examples.
You ran rails server and nothing loaded. Or you’re trying to connect to a remote server and getting nothing back. The first question is always the same: is the port actually open?
Checking port status on Mac takes one command. The trick is knowing which command to use depending on whether you’re checking your own Mac or a remote host.
Checking your own Mac’s open ports
This is the most common case for developers. Your dev server should be running on port 3000, but the browser says it can’t connect. Is the port listening at all?
lsof -i :port (the fast answer)
lsof -i :3000
If something is listening, you’ll see output like this:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ruby 8421 aaron 13u IPv4 0x3f8a2b4c 0t0 TCP *:3000 (LISTEN)
If the output is empty, nothing is bound to that port. Your Rails server isn’t running, or it started on a different port.
For port 8080:
lsof -i :8080
For port 80 (requires sudo since it’s a privileged port):
sudo lsof -i :80
lsof -i | grep LISTEN (see everything at once)
To see all ports your Mac is currently listening on:
lsof -i | grep LISTEN
The output shows every process with an open listening port:
ruby 8421 aaron 13u IPv4 TCP *:3000 (LISTEN)
node 9102 aaron 21u IPv6 TCP *:8080 (LISTEN)
postgres 1234 aaron 5u IPv4 TCP localhost:5432 (LISTEN)
Notice localhost:5432 vs *:3000. Postgres is only accepting connections from the same machine. Rails is accepting from anywhere on the network. That distinction matters when you’re trying to connect from another device.
If you want numeric ports without hostname lookups (faster):
lsof -i -n -P | grep LISTEN
netstat -an | grep LISTEN
netstat gives you a similar view in a different format:
netstat -an | grep LISTEN
Output looks like this:
tcp4 0 0 *.3000 *.* LISTEN
tcp4 0 0 127.0.0.1.5432 *.* LISTEN
tcp6 0 0 *.8080 *.* LISTEN
The address before the port tells you the interface. *.3000 means all interfaces (accessible from the network). 127.0.0.1.5432 means localhost only.
netstat is useful when you want a quick flat list without process names. lsof is better when you need to know which app owns which port.
What the results mean
Something in the LISTEN output: The port is open and a process owns it. If you still can’t connect, the problem is elsewhere (firewall, wrong IP, authentication).
No output from lsof / nothing in netstat: Nothing is listening on that port. The service either isn’t running or it started on a different port.
Output shows 127.0.0.1 or localhost: The service is only accepting local connections. You won’t be able to reach it from another machine or your phone on the same network.
Checking a remote host’s port
When you need to test whether a port is open on a server you don’t control, you can’t use lsof. Instead, you actually try to connect and see what happens.
nc -zv (the right tool)
nc -zv hostname 443
If the port is open:
Connection to hostname port 443 [https] succeeded!
If it’s closed (nothing listening):
nc: connectx to hostname port 80 (tcp) failed: Connection refused
If it’s filtered (firewall dropping packets):
nc: connectx to hostname port 25 (tcp) failed: Operation timed out
“Connection refused” means the server is reachable but nothing is on that port. “Timed out” means a firewall is probably dropping your packets before they arrive.
Real-world examples:
# Is HTTPS working on my server?
nc -zv myserver.com 443
# Is SSH open on this box?
nc -zv 192.168.1.100 22
# Can I reach the database port from this machine?
nc -zv db.internal 5432
You can also check multiple ports at once:
nc -zv hostname 80 443 8080
Interpreting the results
| Result | Meaning |
|---|---|
| Connection succeeded | Port is open, something is listening |
| Connection refused | Port is closed, nothing listening |
| Operation timed out | Firewall is blocking the connection |
| Name or service not known | Hostname doesn’t resolve (DNS problem) |
If a port succeeds but your service still doesn’t work, the problem is at the application layer: wrong credentials, protocol mismatch, the app rejecting the connection.
Common ports to check
When debugging, these are the ports that come up most often:
- 22 (SSH): Can’t SSH in? Check this first.
- 80 (HTTP) and 443 (HTTPS): Web server not responding.
- 3000, 3001, 8000, 8080: Common dev server ports. Rails defaults to 3000, many Node apps use 8080.
- 5432 (PostgreSQL), 3306 (MySQL), 27017 (MongoDB): Database connection issues.
- 25 (SMTP): App can’t send email? Often blocked by ISPs and cloud providers.
Security: what ports is your Mac exposing?
Running lsof -i | grep LISTEN is worth doing occasionally from a security standpoint. Every listening port is a potential entry point. On a laptop, you usually want to see as few open ports as possible.
Common culprits for unexpected open ports:
- Development servers left running (Rails, Node, Webpack)
- Docker mapping ports to the host
- Remote Desktop or Screen Sharing enabled
- AirPlay receiver
- Third-party apps running background services
If you see something you don’t recognize, grab the PID from the lsof output and look it up:
ps aux | grep <PID>
Using macOS firewall
The macOS firewall controls what can connect to your Mac from outside. Check it at System Settings > Network > Firewall (or System Settings > Privacy & Security > Firewall on some versions).
When the firewall is on, other machines can’t reach listening services on your Mac unless you’ve explicitly allowed them. Your Mac can still make outgoing connections.
If your local dev server loads fine in your browser but not from your phone on the same network, the firewall is the likely reason.
GUI option: NetUtil’s port scanner
If you’d rather not type commands, NetUtil includes a port scanner. Enter a hostname and port range, and it shows which ports are open in a table. It’s the direct replacement for the port scanner that used to be in Apple’s Network Utility before it was removed in macOS Monterey.
For regular debugging, the Terminal commands are faster once you know them. lsof -i :3000 is four keystrokes to type once you’ve done it a few times. For occasional checks or when you want to scan a range of ports on a remote server, a GUI tool saves time.
Quick reference
Check if your Mac is listening on a specific port:
lsof -i :3000
See all ports your Mac is listening on:
lsof -i | grep LISTEN
Same with netstat:
netstat -an | grep LISTEN
Check if a remote port is open:
nc -zv hostname 443
Port status on your Mac tells you whether a service is running. Port status on a remote host tells you whether that service is reachable. Two different questions, two different tools.