
"Connection refused." "Connection timed out." "Can't reach the server." Behind almost every one of these is a single question: is the port actually open? Whether you're debugging a database that won't accept connections, a firewall that's silently dropping traffic, or an API that "should be up," checking whether a TCP/UDP port is open is the fastest way to localize the problem.
This guide is a practical, copy-paste reference for checking ports from Windows, macOS and Linux — using telnet, netcat (nc), nmap, PowerShell's Test-NetConnection, and the bash /dev/tcp trick — plus how to read the results and, crucially, how to stop checking by hand and monitor ports continuously instead.
What "Open" Actually Means
A port isn't a thing that exists on its own — it's open only if a process is listening on it and the network path allows you to reach it. When you test a port, you can land in one of three states:
- Open — something is listening and accepting connections. The TCP handshake completes.
- Closed — you reached the host, but nothing is listening on that port. You get an immediate connection refused (the host sends a TCP RST).
- Filtered — a firewall is dropping your packets silently. You get a timeout, not a refusal, because no response comes back at all.
That distinction matters: refused = reached the host, no listener; timeout = something is blocking the path. Keep it in mind as you read the results below.
Quick Reference: One Command Per Platform
If you just need the fastest check for a host and port (here, example.com:443):
| Platform | Command |
|---|---|
| Linux / macOS (netcat) | nc -zv example.com 443 |
| Linux / macOS (bash, no tools) | bash -c "echo > /dev/tcp/example.com/443" && echo open |
| macOS / Linux (nmap) | nmap -p 443 example.com |
| Windows (PowerShell) | Test-NetConnection example.com -Port 443 |
| Any (telnet) | telnet example.com 443 |
The rest of this guide explains each, how to read the output, and the UDP and "what's listening locally" cases.
Linux & macOS
netcat (nc) — the go-to
netcat is the cleanest way to test a remote port. The flags: -z (zero-I/O / scan mode, just check don't send data), -v (verbose).
nc -zv example.com 443
# Connection to example.com port 443 [tcp/https] succeeded!
nc -zv example.com 444
# nc: connect to example.com port 444 (tcp) failed: Connection refused
Add a timeout so a filtered port doesn't hang: nc -zv -w 3 example.com 443 (wait at most 3 seconds).
The /dev/tcp trick (no tools installed)
Stripped-down container or minimal server with no nc, nmap, or telnet? Bash can open TCP sockets itself via the special /dev/tcp/<host>/<port> path:
timeout 3 bash -c "echo > /dev/tcp/example.com/443" && echo "OPEN" || echo "CLOSED/FILTERED"
If the socket opens, it prints OPEN. This works in bash (not sh/dash), and needs no extra packages — invaluable for debugging inside slim Docker images.
nmap — when you want detail
nmap is the most informative: it tells you open vs closed vs filtered explicitly, and can scan ranges.
nmap -p 443 example.com # single port
nmap -p 80,443,8080 example.com # several ports
nmap -p 1-1000 example.com # a range
PORT STATE SERVICE
443/tcp open https
STATE will read open, closed, or filtered — exactly the three states from earlier.
What's listening on this machine?
To see local listeners (not reach a remote host), use ss (modern) or lsof:
ss -tulpn | grep :443 # Linux: t=tcp u=udp l=listening p=process n=numeric
sudo lsof -i :443 # macOS/Linux: which process owns the port
If ss/lsof show nothing on the port, your service isn't listening — the problem is the app, not the network.
Windows
PowerShell: Test-NetConnection (recommended)
Modern Windows doesn't ship telnet by default, but PowerShell has a built-in:
Test-NetConnection example.com -Port 443
ComputerName : example.com
RemoteAddress : 93.184.216.34
TcpTestSucceeded : True
TcpTestSucceeded : True means open. False means closed or filtered. Short form: tnc example.com -Port 443.
See local listeners on Windows
Get-NetTCPConnection -State Listen | Where-Object LocalPort -eq 443
# or the classic:
netstat -ano | findstr :443
The last column of netstat -ano is the PID — match it in Task Manager to find the owning process.
Enabling telnet (if you want it)
telnet is an optional feature on Windows: enable it once with dism /online /Enable-Feature /FeatureName:TelnetClient (or via Turn Windows features on or off), then use it as below.
telnet — Works Everywhere (with a catch)
telnet is the classic cross-platform check. A successful connection clears the screen / shows a connection message; a failure refuses or hangs.
telnet example.com 443
# Trying 93.184.216.34...
# Connected to example.com. <-- OPEN
The catch: telnet gives you no clean timeout and an awkward exit (Ctrl+] then quit). It's fine for a one-off, but nc and Test-NetConnection are better for scripting.
Don't Forget UDP
Everything above (except where noted) tests TCP, which has a handshake you can observe. UDP has no handshake, so "open" is ambiguous — no response can mean open or filtered. Test it explicitly:
nc -zvu dns.example.com 53 # -u for UDP
sudo nmap -sU -p 53 dns.example.com
For UDP services (DNS, NTP, QUIC, game servers), an application-level check — does the service actually answer a real query? — is far more reliable than a raw port probe. This is one reason port checks alone aren't enough (see below).
Reading the Result: A Decision Table
| Symptom | Most likely cause | Where to look |
|---|---|---|
| Connection refused (instant) | Host reachable, no process listening | The service is down or bound to the wrong interface (127.0.0.1 vs 0.0.0.0) |
| Timeout (hangs, then fails) | Firewall/security group dropping packets | Cloud security group, host firewall (ufw/iptables), network ACL |
| Open but app errors | Port open, service unhealthy | App logs — TCP is fine, the application layer isn't |
| Open from server, closed from outside | Bound to localhost or blocked upstream | Listen address + perimeter firewall |
That third row is the trap that bites everyone: a port being open does not mean the service is healthy. A database can accept TCP connections while refusing logins; a web server can complete the handshake while returning 500s.
Why One-Off Checks Aren't Enough
Manually checking a port tells you its state for one second, from one place. Real problems are intermittent and location-dependent:
- A port that's open now can silently close after a deploy, a crash, or an OOM kill at 3 a.m.
- A firewall rule change can filter a port for external users while it still works from inside your network.
- A service can keep the port open but stop doing useful work.
That's the gap between checking a port and monitoring it. Continuous TCP port monitoring connects to the port on a schedule from outside your network and alerts you the moment it stops accepting connections — catching exactly the failures HTTP checks miss. For latency and packet-loss issues on the path itself, pair it with ping monitoring, and for "the port is open but the response is wrong," add response body validation.
How Webalert Helps
Webalert turns a one-off port check into continuous, outside-in coverage:
- TCP port checks that connect to your database, mail, SSH, or custom-service ports on a schedule — and alert when the handshake stops succeeding. See port monitoring.
- Multi-region probes so you catch the "open from the server, blocked for users" case — see why location matters.
- Latency & packet-loss tracking via ping monitoring to catch a degrading path before the port fully fails.
- Application-level validation so an open-but-broken service doesn't read as healthy (content validation).
- Fast alerting to Slack, email, SMS and more the instant a port goes unreachable.
Summary
To check if a port is open: use nc -zv host port (or bash /dev/tcp) on Linux/macOS, Test-NetConnection host -Port n on Windows, or nmap -p n host when you want explicit open/closed/filtered detail. Remember the rule — refused means reachable-but-no-listener; timeout means something is blocking the path — and that TCP has a handshake to observe while UDP needs an application-level test.
But a port check is a single snapshot. Ports drift closed after deploys, firewalls change, and "open" never guarantees "healthy." For anything you care about staying up, monitor the port continuously from outside your network rather than checking it by hand.