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.