Which MySQL metrics reliably predict an imminent outage versus ones that only confirm impact has already started, and why is 'CPU usage' one of the least useful signals for a database specifically?
Quick Answer
Leading indicators are InnoDB buffer pool hit ratio dropping, history list length (undo log backlog) growing, and Threads_running trending up while Threads_connected stays flat, because these reveal internal pressure building before users notice anything. CPU usage is a poor primary signal for MySQL because a database can be in serious trouble — lock-starved, replication-lagged, or thrashing its buffer pool — while CPU sits comfortably low, since waiting and I/O-bound states don't register as CPU load at all.
Detailed Answer
A hospital emergency room's true stress signal isn't how many doctors are physically moving around at any moment — it's how long the waiting room has been filling up and how many patients are queued for a bed. A room could have doctors calmly standing by (low CPU-equivalent) while the actual bottleneck is beds not turning over fast enough (locks, I/O, connections), and by the time doctors themselves look overwhelmed, the real crisis started much earlier upstream.
MySQL's most commonly-watched infrastructure metric, CPU usage, measures compute time spent, which correlates well with query-plan-driven load like heavy sorting or hashing, but says nothing about time spent waiting — locks, disk I/O, network round trips to a replica, or semaphore waits inside InnoDB. A database experiencing serious internal pressure from any of these sources can show flat or even low CPU precisely because threads aren't computing, they're blocked, and blocked threads don't consume CPU cycles. This makes CPU usage a lagging or even entirely absent signal for the failure modes that most commonly cause real MySQL incidents in production.
InnoDB buffer pool hit ratio (the percentage of data page reads served from memory versus requiring a disk read) is a genuine leading indicator: as the working set grows beyond available buffer pool size, hit ratio degrades gradually before query latency visibly spikes, giving an early warning that either the buffer pool needs to grow or the working set needs to shrink (via archiving, sharding, or better indexes). History list length — the size of InnoDB's undo log, which grows when long-running transactions prevent old row versions from being purged under MVCC (MySQL's mechanism for letting readers see a consistent snapshot without blocking writers) — is another strong leading indicator: a growing history list means something is holding a long transaction open, and if left unchecked it directly degrades every subsequent query's performance because InnoDB has more old row versions to scan through.
In production, mature monitoring dashboards for MySQL prioritize buffer pool hit ratio, history list length, Threads_running relative to Threads_connected, and replication lag ahead of CPU and even ahead of raw query latency, specifically because these internal signals predict the latency spike before it happens, giving on-call engineers a window to intervene (killing a long-running transaction, scaling the buffer pool, adding a replica) before customers notice anything. Teams that alert primarily on CPU and query latency consistently get paged only once the incident is already fully user-visible, because those are lagging confirmations rather than early warnings.
The gotcha even experienced teams miss: history list length can grow silently from an application bug that opens a transaction and never closes it (not necessarily a large or complex transaction — a completely trivial SELECT run inside an ORM's auto-transaction wrapper that never commits can hold back purge indefinitely), and this metric climbing has no direct correlation with any specific slow query in the slow query log, since the 'culprit' transaction may not itself be running anything slow — it's just sitting open. This is why history list length has to be monitored as its own first-class signal rather than assumed to be implied by slow-query logging, which will show nothing wrong at all while the real problem quietly compounds in the background.