Most teams monitor their database the same way they'd check a pulse from across the room: they ping a port, see it's open, and move on. The connection succeeds, the health check goes green, and everyone assumes the data layer is fine. It usually is: right up until the moment it isn't, and by then the signal you needed showed up hours ago in a place nobody was looking.
Your database is the heart of your application. Almost every meaningful failure your users experience routes through it: a checkout that hangs, a dashboard that won't load, a background job that silently stops draining its queue. The tragedy is that these failures are observable (the database is practically shouting about them) but a basic uptime check is deaf to everything except "is the socket open."
Let's talk about what real database monitoring looks like, and the three patterns that separate teams who find out from their monitoring from teams who find out from Twitter.
1. Run a real query, not a ping
A TCP handshake proves the network path is alive. It says nothing about whether the database can actually serve a query. A primary can accept connections while its disk is full. A replica can answer pings while it's minutes behind on replication. Connection pooling can hide a database that's refusing new work behind a queue of waiting clients.
The fix is to connect the way your application connects: authenticate, then run a live validation query and assert on the result:
A validation query does three jobs at once: proves connectivity, proves the query engine works, and produces a latency number worth alerting on.
This one change turns your monitor from a network test into an application-level guarantee. If the query returns, authentication works, the planner works, and the storage layer is responding. If it doesn't, you know before your users do.
2. Assert on values to catch silent failures
The most dangerous outages are the ones where every HTTP response is still 200 OK. The API is up. The database is up. But a background worker died two hours ago and orders are quietly piling up unprocessed. Nothing is "down", the business is just silently broken.
You catch these by monitoring the data, not the infrastructure. Run a scheduled query, pull out a specific column, and assert against the value it returns:
Threshold breached: 27 failed orders against a limit of 25. No 500s were thrown to trigger this, only the data knew.
A handful of these assertions cover the failure modes that basic monitoring can't see:
- Ensure background queues are actually draining, not just accepting jobs.
- Validate critical business-logic tables: inventory counts, pending payments, unsent emails.
- Catch silent failures where the HTTP layer happily returns
200while the work never happens.
"Up" is not the same as "working." The outages that hurt most are the ones where every dashboard is green.
3. Measure latency in stages, before it becomes a timeout
Databases rarely fail cleanly. They degrade. Query times creep from 40ms to 140ms to 900ms over a week as a table grows or an index goes stale, and nobody notices until a connection finally times out and takes a user-facing feature down with it.
The signal is in the trend, and the diagnosis is in the breakdown. Splitting a single check into its phases tells you where the time is going: network, TLS, auth, or the query itself:
Now the alert isn't "the database is slow", it's "query execution crossed 100ms while connection and auth stayed flat." That's the difference between a vague page at 3am and a page that already tells the on-call engineer where to look.
When it does fall over, cut time-to-answer
Good monitoring means you find out first. Good incident response means you spend that head start fixing the problem instead of assembling the people who might. The moment a threshold breaks, the right engineers should be paged automatically, an incident channel should already exist, and the context that led to the alert should be waiting for whoever arrives.
This is where correlating the alert with recent changes pays off. A latency spike on payment_intents means a lot more when your monitoring can tie it to the migration that shipped an hour earlier:
Query execution time increased by 400% on payment_intents. This correlates with a missing index on the customer_id column detected during the last migration.
A suggested root cause won't always be right, but even when it just narrows the search, it turns a 40-minute investigation into a 5-minute confirmation. Pair that with a one-click status-page update and you've closed the loop from detection to communication without a war-room scramble.
The takeaway
You don't need an enterprise observability platform to monitor your database well. You need to stop treating "the port is open" as a health check and start treating it like what it is: the least informative signal your database can give you.
Connect the way your app connects. Run a real query and assert on the result. Watch the data for silent failures, and watch latency in stages so you see degradation as a slope, not a cliff. Do that across Postgres, MySQL and Redis, and most of your "how did we not catch this" postmortems simply stop happening.
Because the goal was never to know when the database fell over. It's to catch it while it's still just leaning.
Stop guessing why the DB is slow
Monitor your queries, latency and connectivity in under a minute: no agents, no enterprise contract.
Create your first monitor →