How to Test TCP Connection in Linux: nc, curl, telnet
Test TCP connections in Linux using nc, curl, telnet, and /dev/tcp — verify port reachability, measure response time, and debug connection failures with real examples.
You need to know if a port is reachable before debugging further. Here are the reliable ways to test a TCP connection — and what the output actually tells you.
TL;DR
nc -zv host 8080 # test port — best general purpose
curl -v telnet://host:8080 # curl TCP test
telnet host 8080 # classic, interactive
cat /dev/null > /dev/tcp/host/8080 && echo open || echo closed # no extra tools
nc (netcat): The Standard Tool
nc -zv 192.168.1.100 8080
Flags:
-z— scan mode, don't send data-v— verbose, shows result clearly
Output:
# Success:
Connection to 192.168.1.100 8080 port [tcp/http-alt] succeeded!
# Refused (nothing listening):
nc: connect to 192.168.1.100 port 8080 (tcp) failed: Connection refused
# Timed out (firewall DROP):
nc: connect to 192.168.1.100 port 8080 (tcp) failed: Connection timed out
Refused = something reachable but nothing on that port. Timed out = firewall silently dropping packets, or host unreachable.
Test multiple ports
for port in 80 443 8080 8443; do
nc -zv -w 2 192.168.1.100 $port 2>&1 | grep -E "succeeded|failed"
done
Set a timeout
nc -zv -w 3 host 8080 # 3 second timeout instead of hanging
Test UDP
nc -zvu host 53 # test DNS UDP port
/dev/tcp: No Extra Tools Required
Available in bash without any packages:
# Test if port is open
timeout 3 bash -c 'cat /dev/null > /dev/tcp/192.168.1.100/8080' 2>/dev/null \
&& echo "Port open" || echo "Port closed/filtered"
Useful in minimal containers where nc isn't installed.
curl: Test HTTP and TCP
# HTTP test
curl -sv http://host:8080/health 2>&1 | head -30
# Raw TCP (no HTTP)
curl -v telnet://host:8080
# With timeout
curl -sv --connect-timeout 5 http://host:8080/
# Check just the response code
curl -o /dev/null -s -w "%{http_code}\n" http://host:8080/health
curl -v shows the full TLS handshake and HTTP exchange — useful for SSL debugging.
telnet: Classic Interactive Test
telnet host 8080
- If it connects: you'll see a blank line or a banner. Port is open.
Connection refused: nothing listening.- Hangs: firewall DROP rule.
Press Ctrl+] then quit to exit.
Not installed by default on minimal systems, but widely available.
Measure Connection Time
# Measure TCP handshake time with curl
curl -o /dev/null -s -w "Connect: %{time_connect}s Total: %{time_total}s\n" http://host:8080/
# With nc (measure time to connect)
time nc -zv -w 5 host 8080
Real Examples
Verify a service is reachable from another server
# From app server, test database connectivity
nc -zv db01 5432
# Connection to db01 5432 port [tcp/postgresql] succeeded!
Debug "connection refused" during deployment
# Is the new app listening yet?
while ! nc -z localhost 8080; do
echo "Waiting for app to start..."
sleep 2
done
echo "App is up"
Test port from inside a Docker container
docker exec mycontainer nc -zv db 5432
# If nc isn't in container:
docker exec mycontainer bash -c 'cat /dev/null > /dev/tcp/db/5432 && echo open'
Test through a specific interface
# Force connection through eth1
nc -s 192.168.2.10 -zv destination.host 443
SSL/TLS port test
# Test TLS handshake
openssl s_client -connect host:443 -servername hostname < /dev/null 2>&1 | grep -E "Verify|Cipher|subject"
# Quick TLS check
curl -sv https://host:443/ 2>&1 | grep -E "Connected|SSL|TLS|Certificate"
Interpreting Results
| Result | Cause | Next step |
|---|---|---|
succeeded |
Port is open and reachable | Service is running |
Connection refused |
Port not listening | Check if service is running: ss -tlnp |
Connection timed out |
Firewall DROP rule or host unreachable | Check firewall, check routing |
Name or service not known |
DNS failure | Check DNS: dig hostname |
No route to host |
Routing problem | Check ip route, check if host is up |
Common Mistakes
Mistake 1: Not setting a timeout
Without -w 3 or --connect-timeout, nc and curl wait the OS default (30+ seconds) on timed-out connections. Always set a timeout in scripts.
Mistake 2: Confusing refused vs timed out Refused = firewall with REJECT, or no service. Timed out = firewall with DROP. REJECT is more user-friendly but exposes that something is there. DROP reveals nothing.
Mistake 3: Testing from the wrong host
A service can be reachable locally (nc -zv localhost 8080) but not from external hosts if it's bound to 127.0.0.1. Always test from the actual client perspective.
Quick Reference
nc -zv host port # test TCP port
nc -zv -w 3 host port # with 3s timeout
nc -zuv host 53 # test UDP
curl -o /dev/null -s -w "%{http_code}" http://host/ # HTTP status
timeout 3 bash -c 'cat /dev/null > /dev/tcp/host/port' # no tools needed
openssl s_client -connect host:443 # TLS test
Conclusion
nc -zv host port is the cleanest test — works for any TCP port, clear success/failure output. Add -w 3 to avoid hanging on filtered ports. For HTTP specifically, curl -sv gives you headers and TLS info. In minimal environments without nc, /dev/tcp is always available in bash.
Related: Cannot Connect to Server Linux — full diagnostic workflow when nc shows a problem. Check Open Ports in Linux: ss vs netstat — verify what's listening on the server side.