ObservabilityintermediatePro runbook

Find what is actually burning CPU

CPU is pinned and pg_stat_activity is full of sessions — but most of them are waiting, not working. One column separates the backends on the CPU from the backends stuck behind something else, and it decides which fix is even relevant.

Problem

What you're actually looking at

The symptom as it shows up on a real server.

A host CPU graph tells you the box is saturated. It cannot tell you which backend is saturating it, and the obvious query — everything in pg_stat_activity that is not idle — mixes two completely different populations. A backend blocked on a lock is not using CPU at all, yet it looks identical in a naive listing.

Meridian Freight's checkout database sits at 98% CPU through a peak hour. The on-call engineer lists active sessions and sees forty of them. Thirty-six are queued behind a lock and consuming nothing; four are running an analytics query a dashboard is re-firing every few seconds. Reading the list without separating the two sends the fix in entirely the wrong direction.

In plain English

When PostgreSQL runs a query it is either doing work, or it is stopped waiting for something — a lock, the disk, or the client. Both of those show up as "active", which is why a list of busy sessions is so misleading during a CPU incident: most of the rows may be sessions that are stopped, not sessions that are burning the machine. There is one column that tells them apart. If a session has no wait reason recorded, nothing is holding it up, so it is genuinely running on a CPU right now. If it does have a wait reason, it is queued and consuming almost nothing. Split the list that way and the handful of real culprits is immediately obvious — and it also tells you whether you have a CPU problem at all, or a lock problem wearing a CPU costume.

ProCaptured evidence where the run produced it

Full runbook for this incident

The scenario above is free. What Pro unlocks is the fix: how to identify find what is actually burning cpu, the exact SQL to trace it, PostgreSQL 18 output for the steps we captured, the resolution path, and how to stop it recurring.
  • The full identify checklist — the exact signals that tell you it's this incident
  • Every diagnostic query; PostgreSQL 18 output is attached only to the steps we captured
  • The resolution path and the pitfalls that make it worse
  • Mitigation steps to stop it recurring, plus a verify-you're-done query

Connected

How this connects to the rest of the library

A live view of this page's real cross-references — what explains it, what fixes it, what to tune, and where to go next. Every link is an authored relationship, not a guess.

Open in the interactive map →