Skip to content

Databases

The database monitors connect to your PostgreSQL, MySQL/MariaDB or MongoDB server the way your application does, run a query, and check the result. Unlike a TCP check on port 5432, this proves the server accepts connections, authenticates you, and actually answers — and it records the connect + query latency on every check.

Three monitor types, one behaviour:

TypeSchemes acceptedDefault portDefault query
PostgreSQLpostgres://, postgresql://5432SELECT 1
MySQLmysql://, mariadb://3306SELECT 1
MongoDBmongodb://, mongodb+srv://27017{ "ping": 1 }

MariaDB speaks the MySQL protocol — use the MySQL type.

Agentfr-dc3 1 · connect (TLS) + auth 2 · SELECT count(*) FROM jobs … 3 · result: 7 · 38 ms db.example.com:5432 RESULT connected, query ran, 7 < 10 → up connected but result off threshold → failure refused / auth failed / timeout → failure user / password are stored encrypted and never appear in the URL, alerts, status pages or exports — the URL is saved as postgres://db.example.com:5432/app
  1. The agent opens a connection to the server (TLS when the URL asks for it) and authenticates with the monitor’s user and password.
  2. It runs the configured query — or the type’s default.
  3. The result is compared to the optional result check. Connection refused, authentication failure, a query error or a timeout all count as a failed check; a result outside the expected value counts as a failed check too.

Latency is the full connect + query time, so a database that is getting slower shows up as a trend on the monitor’s chart long before it stops answering.

SettingDescriptionDefault
Connection URLpostgres://host:5432/dbname?sslmode=require, mongodb://host1,host2/admin?replicaSet=rs0&tls=true
Database userLogin used for the check
Database passwordStored encrypted
Test querySQL statement, or a MongoDB command document as JSONSELECT 1 / { "ping": 1 }
Result checkOperator + expected value applied to the query result (optional)none
Skip TLS validationAccept a self-signed certificateoff
IntervalCheck frequencyplan-dependent
TimeoutFixed check budget, connect + query (not configurable)5s

Paste the connection URL exactly as your provider gives it, credentials included. Anything before the @ is moved to the user and password fields and the URL is saved without it:

you paste mongodb://monitoring:s3cret@node1.example.net,node2.example.net/admin?replicaSet=rs0&tls=true
saved URL mongodb://node1.example.net,node2.example.net/admin?replicaSet=rs0&tls=true
user monitoring (encrypted)
password s3cret (encrypted)

The URL is what the monitors list, alert messages, public status pages, the audit log and the GDPR export show. The user and password are encrypted at rest, masked as *** in the API and in every export, and scrubbed from error messages. This applies to every monitor type — an https://user:password@host HTTP target is split the same way.

Use a read-only database user created for monitoring. The query runs with that user’s privileges, nothing else limits it.

The URL decides whether TLS is used, with each engine’s own convention:

  • PostgreSQL — ?sslmode=require (or verify-ca, verify-full)
  • MySQL / MariaDB — ?ssl-mode=REQUIRED (or tls=true)
  • MongoDB — ?tls=true; mongodb+srv:// URLs always use TLS

The server’s certificate is validated against the public roots. For a self-signed certificate, tick Skip TLS certificate validation on the monitor.

The query result is reduced to one value:

  • SQL — the first column of the first row. SELECT count(*) FROM jobs WHERE status = 'stuck' gives a number; SELECT pg_is_in_recovery() gives t/f.
  • MongoDB — the command’s reply document. Pick a field with a dot path (ok, members.0.stateStr, repl.setName); leave the path empty to compare the whole reply.

Then choose an operator (==, !=, contains, >, <, >=, <=) and the expected value. Numeric operators compare numbers; the others compare text.

Examples:

EngineQueryCheckMeaning
PostgreSQLSELECT count(*) FROM jobs WHERE status='stuck'< 10job queue is not backing up
PostgreSQLSELECT extract(epoch from now() - pg_last_xact_replay_timestamp())< 30replica lag under 30 s
MySQLSHOW STATUS LIKE 'Threads_connected'(first column is the name — use a subquery)
MySQLSELECT count(*) FROM information_schema.processlist< 200connection count under 200
MongoDB{ "replSetGetStatus": 1 }members.0.stateStr == PRIMARYnode 0 is the primary
MongoDB{ "serverStatus": 1 }connections.current < 500connection count under 500

Without a result check, connecting and running the query successfully is the whole check.

A database that is not reachable from the internet — and most should not be — is monitored from a private agent running inside your network. The check is identical; only the agent doing it changes. Public regions refuse targets that resolve to private addresses.

Connect + query time is recorded on every check and drives the same latency chart, percentiles and alerts as an HTTP monitor.