Blog

TCP port monitoring: when a port check is the right tool, what it proves and how to combine it with HTTP checks

A TCP port check tells you something is listening, not that it works. Here is when to use one, how to set timeouts and how to layer it with HTTP and app-level checks.

TCP port monitoring opens a TCP connection to a host and port at a fixed interval and alerts when the connection is refused or does not complete within a timeout. It is the right check for services that do not speak HTTP, such as databases, mail servers, message brokers, game servers and custom protocols. Keep in mind that an open port only proves something is listening, so pair the port check with an HTTP or application-level check for anything that matters.

This guide covers what a port check actually measures, where it fits, how to pick timeouts and how to combine it with other checks so an alert tells you where the problem is, not just that there is one.

What a TCP port check actually does

A port check performs the TCP three-way handshake: the probe sends SYN, the server answers with SYN-ACK, the probe sends ACK. If that completes, the check counts as up and the connection is closed. No application data is exchanged unless the check is configured to read a banner or send a payload.

There are three outcomes, and each points somewhere different:

  • Connected: the host is reachable and a process (or the kernel on its behalf) accepted the connection.
  • Connection refused: the host answered with a TCP reset. The machine is up and reachable, but nothing is listening on that port, or a firewall rule is set to REJECT.
  • Connect timeout: no answer at all. Typical causes are a firewall that DROPs packets, a host that is down, a routing problem or a security group that does not allow the probe.

That distinction is useful during an incident. Refused usually means "the process died or is bound to the wrong interface". Timeout usually means "network, firewall or the whole machine".

When TCP port monitoring is the right tool

Use a port check when the service has no HTTP endpoint you can hit, or when you want a cheap, protocol-independent signal next to a deeper check. Common cases:

  • Databases: PostgreSQL on 5432, MySQL and MariaDB on 3306, Redis on 6379, MongoDB on 27017.
  • Mail: SMTP on 25, submission on 587, SMTPS on 465, IMAPS on 993. A dead submission port means users cannot send mail even if your webmail loads fine.
  • Message brokers and queues: AMQP on 5672, Kafka brokers on 9092, MQTT on 1883 or 8883.
  • Game servers: only if the game protocol runs over TCP, for example a Minecraft Java server on 25565. Many game servers use UDP, and a TCP check against them tells you nothing.
  • Custom services: internal RPC endpoints, license servers, SFTP or proprietary protocols where you control the port but not the protocol tooling.

For a public website or REST API, an HTTP check is almost always better, because it validates status codes and response content. A TCP check on port 443 of your web server will stay green while the application returns 502 to every request.

What an open port does and does not prove

A successful TCP connect proves that something on that port completed a handshake. It does not prove that the service behind it can do its job.

What it does prove:

  • The host is up and reachable from the probe location.
  • Firewalls, security groups and routing allow the path.
  • Something is bound to that port on an interface the probe can reach.

What it does not prove, with real failure modes that pass a port check:

  • Hung application. On Linux, the kernel completes the handshake and places the connection in the accept backlog before the application calls accept(). A deadlocked process can keep passing port checks until that backlog fills up.
  • Database at its connection limit. PostgreSQL accepts the TCP connection and only then rejects the session with "too many clients already". The port is open, your app is down.
  • Proxy or load balancer in front. If HAProxy, nginx or a cloud load balancer terminates the connection, the port check tests the proxy, not the backend.
  • Disk full, read-only filesystem, replication broken. The listener is fine, writes fail.
  • TLS problems. An expired or wrong certificate on 465, 993 or 8883 does not affect the TCP handshake at all.

That list is the reason to treat a port check as a reachability signal, not a health signal.

How to test a port by hand before you monitor it

Before creating a monitor, confirm from outside the network that the port behaves the way you expect. These commands show the same three outcomes the monitor will see:

# connect test with a 5 second timeout
nc -vz -w 5 db.example.com 5432

# measure how long the connect takes
time nc -z -w 5 db.example.com 5432

# without netcat, using bash
timeout 5 bash -c '</dev/tcp/mail.example.com/587' && echo open

# read the SMTP banner, a healthy server answers with 220
nc -w 5 mail.example.com 25

# TLS ports: check the handshake and certificate, not just the socket
openssl s_client -connect mail.example.com:993 -servername mail.example.com </dev/null

If the external test fails, check the server side:

# is anything listening, and on which address?
ss -ltnp | grep 5432

A listener on 127.0.0.1:5432 instead of 0.0.0.0:5432 or the private interface is one of the most common reasons for "connection refused" after a config change or package upgrade.

Choosing timeouts and intervals for port checks

A TCP handshake is one round trip, so a healthy connect is usually fast. Measure it first with the time nc command above from a few locations, then set the timeout well above the normal value but well below the check interval.

Reasonable starting points for a connect-only check:

  • Timeout: 5 to 10 seconds. Lower values catch overload sooner but trigger on transient packet loss. Values above 15 seconds mostly delay alerts for a host that is already gone.
  • Interval: 1 minute for production databases and mail, longer for internal or low-impact services.
  • Confirmation: do not alert on a single failed connect. Require a failure from more than one location or more than one consecutive check.

A refused connection is a much stronger signal than a timeout, because a reset is an explicit answer from the target host. Timeouts are where most false alarms come from. The details of retries, multi-location confirmation and split thresholds are covered in the guide on reducing false positive alerts with multi-region checks and realistic timeouts.

Monitoring ports that should not be public

Your database port should usually not be reachable from the internet, and opening it just so an external probe can connect is a bad trade. Three options that do not weaken your setup:

  1. Monitor what is already public. Check the HTTP API that depends on the database. If the API fails while the host is reachable, you investigate the database from inside.
  2. Allowlist probe IPs only where the port is already exposed. For mail servers and game servers the port is public by design, so an external port check costs nothing extra.
  3. Run an internal check and push the result. A small script inside the network runs an application-level test and calls a heartbeat URL on success. If the ping stops arriving, you get alerted.

An internal push check for PostgreSQL and Redis can look like this, run every minute from cron:

#!/bin/sh
set -e
pg_isready -h 10.0.0.5 -p 5432 -t 5
redis-cli -h 10.0.0.6 -p 6379 PING | grep -q PONG
curl -fsS -m 10 https://example.com/your-heartbeat-url >/dev/null

This tests more than a port check could, because pg_isready and PING talk to the actual service. The pattern works with any push-based monitor; the mechanics are described in the documentation on heartbeat monitors for scheduled jobs.

Combining TCP port monitoring with HTTP checks

The real value of a port check comes from layered checks: a few monitors at different levels of the stack, so the pattern of failures tells you where to look. A typical setup for a small SaaS:

  • HTTPS check on the public app and API, validating status code and a keyword in the response.
  • TCP check on SMTP submission (587) of the mail relay.
  • TCP or internal push check on PostgreSQL and Redis.
  • Ping check on the database host, if ICMP is allowed.

Reading the combination:

  • HTTP fails, database port up, host ping up: application problem, or the database is up but unhealthy (connection limit, locks, disk).
  • HTTP fails, database port refused, host ping up: the database process stopped or rebound to another interface.
  • Database port times out, host ping fails: host down or network path broken.
  • Everything fails at once from all locations: upstream network, DNS or provider outage.

For alert routing, the HTTP check is usually the one that should page someone, because it reflects what users see. Port checks on dependencies are useful as context in the same alert channel, so the on-call person sees "API down" and "Postgres refused" side by side instead of guessing.

Setting up a TCP port monitor step by step

  1. List every non-HTTP service your product depends on, with host, port and whether the port is public.
  2. Test each one by hand with nc -vz -w 5 from outside your network and note the connect time.
  3. For public ports, create a TCP monitor with a 5 to 10 second timeout and a 1 minute interval.
  4. For private ports, use an internal application-level check that pushes a heartbeat instead of exposing the port.
  5. Require confirmation from multiple locations or consecutive failures before alerting.
  6. Add an HTTP check for every user-facing endpoint that depends on those services.
  7. Route the HTTP alert to whoever is on call and send dependency alerts to the same channel for context.
  8. Stop the service in a staging environment once and confirm the alert arrives with a useful message.

TCP port monitoring with m0nitor

m0nitor supports TCP port checks alongside HTTP(S), UDP port, SSH, ping, DNS, SSL certificate expiry and heartbeat monitors, so the layered setup above can live in one place. Checks run from distributed probes in several regions, and an outage has to be confirmed by multiple locations before an alert fires. The available types are listed on the page about uptime monitoring and monitor types. Alerts can go to email, Slack, Microsoft Teams, PagerDuty and other alert channels and integrations. Any tool that can do TCP connects with multi-location confirmation will work for the approach described here.

FAQ

What is the difference between TCP port monitoring and HTTP monitoring?

A TCP check only verifies that a connection to a port can be established. An HTTP check sends a request and evaluates the response, including status code and content. HTTP checks catch application errors that a TCP check misses, so use TCP for non-HTTP services and HTTP wherever an endpoint exists.

Can I monitor UDP ports the same way?

No. UDP has no handshake, so there is no equivalent of a successful connect. A UDP check has to send a payload and wait for a response, and a missing reply can mean the service is down or simply chose not to answer. Use a dedicated UDP check with a protocol-appropriate payload.

What timeout should a TCP port check use?

Measure the normal connect time from several locations and set the timeout well above it. For most services, 5 to 10 seconds is a reasonable starting point. Combine it with confirmation from multiple locations or consecutive failures so single dropped packets do not cause alerts.

Is it safe to expose a database port so it can be monitored?

Generally not. Keep database ports private and monitor them from inside the network with an application-level check that pushes a heartbeat, or monitor the public API that depends on the database. If you must allow external probes, restrict access to their IP addresses and require TLS and authentication.

Product

  • Pricing
  • Features
  • Integrations
  • Security
  • Free network check

Features

  • Uptime monitoring
  • Status pages
  • Alert workflows
  • Incident management
  • Dependencies
  • AI assistant
  • Global infrastructure
  • On-call schedules
  • Enterprise SSO

Use cases

  • Websites for free
  • Cron jobs
  • SSL certificates
  • Databases
  • IP blacklists
  • GDPR compliance

Resources

  • What is a status page?
  • Documentation
  • API
  • MCP server
  • Monitoring glossary
  • Free tools
  • SLA calculator
  • SSL checker
  • DNS lookup
  • Blog
  • Changelog
  • About
  • Contact

Compare

  • Free uptime monitoring
  • UptimeRobot
  • Better Stack
  • Pingdom
  • StatusCake
  • Uptime Kuma
  • Hyperping
  • Atlassian Statuspage
  • Instatus
  • Cachet
  • Freshping