When engineers start ignoring pages, the fix isn’t a memo about vigilance. It’s a redesign of what earns the right to interrupt a human being at 3 AM.
There is a particular kind of silence that should terrify an engineering leader: the silence of an on-call engineer who has stopped reading their pages carefully. Not because they’re lazy, not because they don’t care, but because three months of 2 AM pages for transient blips that resolved themselves have taught their nervous system a very rational lesson — most of these don’t matter, and the ones that do will probably page again in a more dramatic way.
This is alert fatigue, and it is almost never a people problem. It is a signal-to-noise problem, and it is entirely the responsibility of whoever designed the alerting system to fix.
The Mechanism of Fatigue
Human attention doesn’t degrade gracefully — it degrades categorically. After enough false positives, the brain doesn’t get “somewhat less careful” about alerts; it builds a filter that pattern-matches “alert from this source” to “probably nothing” and stops engaging critical thinking at all. This is the same mechanism that makes car alarms useless in a parking lot — everyone’s brain has learned that 99.9% of car alarms are wind, not theft, so the response to all of them, including the real one, is to ignore it.
The dangerous part is that this filter is not consciously chosen. Engineers do not decide one day, “I will ignore pages.” Their attention system makes the decision for them, silently, based on the accumulated evidence of every false alarm that preceded it. By the time a team notices the problem, it’s usually already been happening for months, discovered only when a genuinely critical page gets acknowledged forty minutes late.
Auditing Your Alerts: The Only Diagnostic That Matters
If you suspect your team has alert fatigue, don’t ask them. Ask their pager. Pull the last 90 days of every page sent to a human, and classify each one into exactly one of three buckets:
- Actionable: the page required a human to take a specific action that a machine could not have taken automatically.
- Self-resolved: the underlying condition cleared before or immediately after a human looked at it, requiring no action.
- Duplicate/noise: the page was a restatement of an already-known, already-being-worked issue, or fired on a condition that doesn’t actually indicate a problem.
Most teams that run this audit for the first time are shocked by the ratio. It is common to find that 60-80% of pages fall into the second and third buckets. If fewer than half of your pages result in a real action, you do not have an alerting system — you have a noise generator that occasionally, by accident, contains useful information.
The Core Principle: Alerts Should Describe Symptoms, Not Causes
The most common architectural mistake in alerting is paging on causes instead of symptoms. A cause-based alert says “CPU usage exceeded 90%.” A symptom-based alert says “the checkout API’s error rate exceeded 1% for five consecutive minutes.”
The difference matters enormously in practice. High CPU is not inherently bad — a batch job intentionally saturating a worker node at 3 AM is a feature, not an incident. But an elevated customer-facing error rate is always worth waking someone up for, because it means real users are having a real bad time right now.
Symptom-based alerting has a second, less obvious benefit: it is naturally resistant to the “alert explosion” problem, where a single root cause (say, a downed database) triggers forty different cause-based alerts from forty different services that all depend on it. A well-designed symptom-based alert set will often produce exactly one page — from the service closest to the user — even when the underlying failure ripples through a dozen systems.
Every Alert Needs a Runbook, or It Shouldn’t Exist
A page that arrives with no context and no suggested next step is not an alert, it’s an anxiety generator. Before an alert goes live, it should be able to answer, in the notification itself or one click away:
- What is broken, in user-facing terms? Not “p99 latency alert fired” but “checkout is slow for roughly 1 in 20 customers.”
- What has already been checked automatically? If the alert fired because of a known flaky dependency, say so, so the human doesn’t waste ten minutes rediscovering what the alerting system already knew.
- What is the very first diagnostic step? A link to the specific dashboard, the specific log query, the specific recent deploy — not a generic “check Grafana” instruction that requires the responder to reconstruct context from scratch at 3 AM.
- Is this urgent enough to wake someone up, or can it wait for business hours? This should be a property of the alert’s severity, decided in advance and calmly, not improvised by a groggy human deciding whether to hit snooze.
If a team cannot write this runbook for an alert, that is itself a useful signal: it usually means the alert doesn’t actually correspond to a well-understood failure mode, and firing it in production is premature. Better to spend a sprint understanding the failure mode first.
Severity Tiers Are Not Optional
Not every problem deserves the same response. A mature alerting system has at least three tiers, and treats moving something between tiers as a real, considered decision rather than a default:
- Page (wakes a human immediately, any hour): reserved for issues causing active, current user harm that cannot self-heal — data loss risk, complete service outage, security incidents in progress.
- Ticket (goes into a queue, reviewed next business day): for issues that are real but not urgent — a slow memory leak that will need attention in a week, a certificate expiring in three weeks, a disk that will fill up in four days at current growth rate.
- Dashboard-only (no notification, just visibility): for informational signals worth tracking over time but not worth interrupting anyone about — request volume trends, cache hit ratios, deploy frequency.
The discipline here is resisting the temptation to page on everything “just in case.” Every alert promoted to paging severity that turns out to be non-actionable is a withdrawal from the team’s trust in the pager, and that trust, once spent, is expensive to rebuild.
Deduplication and Correlation: Fixing the Alert Storm
Even with perfect symptom-based alerts, a large enough incident will still generate multiple related pages — the checkout API alert, the payment gateway alert, and the database connection pool alert might all fire within ninety seconds of the same root cause. Left unaddressed, this trains on-call engineers to associate incidents with a wall of simultaneous notifications, which is exhausting and makes it harder, not easier, to find the actual root cause.
Modern alerting pipelines solve this with correlation: grouping alerts that fire within a short time window and that share upstream dependencies into a single incident, with one page sent and the related alerts attached as context rather than as separate interruptions. This is not a nice-to-have — for any team running more than a handful of interdependent services, it is the difference between an on-call engineer who can triage in ninety seconds and one who spends the first ten minutes of a real incident just closing duplicate notifications.
Maintenance Windows and Suppression Rules
A related and often-neglected source of noise is planned maintenance: deploys, database migrations, and infrastructure upgrades that predictably trigger transient alerts as pods restart, connections drop, and metrics briefly wobble. Without explicit suppression rules tied to a maintenance window, every planned change generates a burst of pages that responders quickly learn to associate with normal, expected activity rather than genuine risk, which quietly retrains the same dangerous pattern-matching described earlier, just triggered by your own deploy pipeline instead of an external failure.
Mature alerting systems let you register a maintenance window in advance, tied to the specific services affected, and automatically suppress or downgrade alerts from those services for the duration, while still allowing an alert to escalate normally if the observed impact clearly exceeds what a routine deploy would cause. This distinction, between suppressing noise you expect and staying alert to genuine surprises, is what keeps planned change from silently degrading the team’s trust in the pager.
Fixing Fatigue Once It Exists
If your audit reveals a genuinely fatigued team, the fix is not a training session on the importance of vigilance. It is a structural cleanup, best done as a dedicated project with an explicit owner:
- Delete first, tune second. For any alert with an actionable rate below 10% in your 90-day audit, disable it entirely rather than trying to tune its threshold. A bad alert tuned to fire less often is still a bad alert; it just interrupts people less often while still contributing zero value on the occasions it does fire.
- Rewrite the survivors as symptom-based. For everything that remains, ask whether it’s actually measuring user impact or just a proxy metric that used to correlate with user impact three architecture changes ago.
- Attach a runbook to everything that pages. No exceptions. If you can’t write one, it doesn’t page yet.
- Re-run the audit in 90 days. Alert fatigue is not a one-time cleanup — it’s an ongoing tax that every new alert can reintroduce if nobody is responsible for the overall signal-to-noise ratio of the paging system.
Escalation Policies Are Part of the Alert Design, Not an Afterthought
Even a perfectly tuned, symptom-based, runbook-attached alert can still contribute to fatigue if the escalation policy routing it is badly designed. A common but underappreciated failure is configuring an alert to page the entire team simultaneously for every incident, regardless of severity, which trains everyone except the one person who actually responds to associate pages with someone else probably handling it, diffusing responsibility until, on a bad day, nobody responds quickly because everyone assumed someone else already had.
Well-designed escalation policies mirror the alert’s own severity tiering: a single primary on-call gets paged first, with an automatic, time-boxed escalation to a secondary if the primary doesn’t acknowledge within a few minutes, and a further escalation to a team lead or manager only if both the primary and secondary miss it. This creates clear, unambiguous ownership of every page, at every moment, without needing to wake the whole team for problems one person can competently handle alone.
Escalation policies also need their own audit cadence, separate from the alert content audit. Team rosters change, people leave, and phone numbers get reassigned, so an escalation policy referencing someone who left the company months ago is a silent failure waiting for the worst possible moment to become visible, usually during the exact incident it was supposed to help resolve.
The Cultural Piece That Actually Matters
None of this works if engineers feel unsafe deleting an alert that a senior engineer wrote three years ago. Make it explicit, ideally in writing from leadership, that alerts are software — they can have bugs, they can become outdated, and deleting a bad alert is a contribution, not an act of disrespect to whoever wrote it. The team that treats their alerting configuration as a living, reviewed, owned piece of software will have an on-call rotation people are willing to join. The team that treats it as sacred, untouchable legacy will eventually run out of people willing to hold the pager at all.
Alert fatigue feels like a people problem because the symptom shows up in people — missed pages, slow responses, burnout, attrition. But the cause is almost always upstream, in a system that was allowed to accumulate noise faster than anyone cleaned it up. Fix the system, and the “personality problem” disappears on its own.
Comments 15
The car alarm analogy is perfect. Our on-call rotation collectively developed the exact same 'probably nothing' reflex after months of noisy CPU alerts.
We ran the 90-day audit described here and found over 70% of our pages were self-resolved or duplicates. Genuinely shocking once we actually measured it instead of assuming.
Symptom-based versus cause-based alerting is the single highest-leverage change we made last year. Paging on error rate instead of CPU cut our overnight pages by more than half.
The point about every alert needing a runbook or it shouldn't exist is a great filter. We deleted a third of our alerts simply because nobody could write one.
Escalation policy design deserves way more attention than it usually gets. We had exactly the 'everyone pages, so nobody responds fast' problem described here for over a year.
How long did it take to notice the diffusion-of-responsibility pattern? We only caught it after a real incident sat unacknowledged for eleven minutes.
Almost exactly the same story for us, eight minutes unacknowledged during a payment outage is what finally got budget approved to fix the policy.
Alert correlation and deduplication changed our incident response more than any dashboard redesign. Going from twelve pages to one grouped incident during a real outage was a huge relief.
The severity tier breakdown into page, ticket, and dashboard-only is exactly what we needed. We'd been treating every alert as pageable by default out of caution, which backfired badly.
Maintenance window suppression is something we still don't do well. Every deploy generates a burst of noise that trains people to ignore alerts right when they should be watching closest.
'Delete first, tune second' is refreshing advice. We spent months tuning thresholds on alerts that should have just been deleted outright.
Same experience here. Tuning a bad alert just makes it a quieter bad alert, it doesn't make it a good one.
The cultural point at the end is the real crux of it. Nobody wants to delete an alert a senior engineer wrote years ago even when it's clearly useless now.
Re-running the audit every 90 days is a good discipline. We did ours once, felt proud, and then let noise creep back in over the following year without noticing.
This should be mandatory reading before anyone is allowed to add a new PagerDuty alert. Would have saved our team a lot of burnout two years ago.