---
title: "Monitor a TCP port"
description: "Create a TCP monitor in the dashboard or via the API and MCP, and see the full list of ports the API allows."
doc_version: "1"
last_updated: "2026-10-14"
---

## What it does

A TCP monitor connects to a host and port on each check interval and confirms the connection succeeds — no HTTP request, no response body, just "can we open a socket." Use it for databases, SSH, SMTP, or any other service that doesn't speak HTTP.

## Set it up in the app

1. In the dashboard, click **Add** to create a monitor.
2. Set **Type** to **TCP**.
3. Enter a **Name** (for example `prod-postgres`).
4. Enter the target in the **Host:port** field, for example `db.example.com:5432`.
5. Click **Add**.

![Creating a TCP monitor in the UptimeMonitoring dashboard, with Type set to TCP and Host:port set to db.example.com:5432](/_astro/tcp-monitors-1-create.CKCE6ilH.png)

The dashboard's port field is free text with a hint listing a curated set of common ports — see [Plan limits](#plan-limits) below for why the real, complete allowed list is longer than the hint.

## Do the same through the API or MCP

```bash
curl -X POST https://api.uptimemonitoring.com/api/v1/monitors \
  -H "Authorization: Bearer $UPTIMEMONITORING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "prod-postgres",
    "url": "tcp://db.example.com:5432",
    "type": "tcp"
  }'
```

The `url` field takes `host:port` or `tcp://host:port` — no path, query, or scheme other than `tcp://`. `expected_status` and `body_match` are ignored for `type: "tcp"`. TCP and ping monitors return `state.status: "unknown"` in the create response; the next scheduled check fills in `up` or `down`. See [Monitors](/docs/monitors/) for the full create/update/delete reference.

Through MCP, ask your agent to create a monitor and give it the host:port target and `type: tcp`; the `create_monitor` tool accepts the same `url`/`type` shape. See [Use UptimeMonitoring through MCP](/docs/mcp/).

## Plan limits

The account's real, complete allowed-port list comes from um-api's `checker.AllowedTCPPortsList()` (`internal/checker/ssrf.go`), backed by the `allowedTCPPorts` map in `internal/checker/checker.go`. Don't treat the list below as fixed — it's a snapshot of what `AllowedTCPPortsList()` returns as of this writing, not a forward compatibility promise:

```
21, 22, 25, 80, 110, 143, 443, 465, 587, 993, 995, 2222,
3000, 3306, 5000, 5432, 6379, 8000, 8080, 8443, 8888, 27017
```

The dashboard's port hint shows a narrower, curated subset of eight common ports (`80, 443, 8080, 8443, 3000, 5000, 8000, 8888`) as a convenience — it's not the complete list, and it doesn't validate the port itself. The API accepts any port from the complete list above, whether or not the dashboard's hint mentions it.

If you create a monitor with a port outside the complete list, the API rejects it with a `400` whose message echoes the same list:

```json
{"error": "port 11211 is not allowed for TCP monitors; allowed ports: 21, 22, 25, 80, 110, 143, 443, 465, 587, 993, 995, 2222, 3000, 3306, 5000, 5432, 6379, 8000, 8080, 8443, 8888, 27017"}
```

See [Monitors](/docs/monitors/) for the shared monitor limits (name length, monitor count caps).

## Troubleshooting

**"port is not allowed for TCP monitors."** The port you targeted isn't on the allowed list above. Check the exact port number in your `url` — a typo'd port (like a container's internal port instead of its published one) is a common cause.

**The monitor shows `unknown` right after creation.** That's expected for TCP monitors — the immediate test check that HTTP monitors get doesn't apply here. Wait for the next scheduled check (up to `interval_sec` seconds later).

**Connection refused or timeout, but the port is allowed.** The allowed-port check only confirms the port is on UptimeMonitoring's list — it doesn't guarantee the target host accepts connections on it. Confirm the service is actually listening and reachable from the public internet; UptimeMonitoring's probes can't reach hosts behind a private network or firewall allowlist that excludes them.