Metric · Observability

What is MTBF, and how do you measure it in Metabase?

MTBF — mean time between failures — is the average operating time between one failure and the next: total uptime divided by the number of failures. It's the failure-frequency half of reliability, paired with MTTR as the recovery half. Measure it in Metabase from incident records synced from PagerDuty, incident.io, or Datadog.

TL;DR — Time between consecutive incident starts per service, averaged per window. The reliability identity ties it together: availability ≈ MTBF ÷ (MTBF + MTTR). Fail less often or recover faster — MTBF tells you which one is improving.

What MTBF measures

It measures how long a service runs before something breaks — failure frequency expressed as operating time. That makes it the complement of response metrics: MTTD and MTTA measure how fast you notice and respond, MTTR how fast you recover, and MTBF how long the peace lasts. Because availability ≈ MTBF ÷ (MTBF + MTTR), a service with a 30-day MTBF and a 1-hour MTTR sits at roughly 99.86% — and the decomposition shows whether the next point of availability comes cheaper from preventing failures or shortening them.

What data does it need?

  • An incidents table: started_at, resolved_at, service_name, severity, environment.
  • A written failure definition — typically Sev-1/Sev-2 in production — applied as a filter in the model, consistent with incident count.
  • Source: PagerDuty, incident.io, or Datadog incident exports via Airbyte or scheduled syncs into the warehouse.

SQL patterns

MTBF per service per quarter (gaps between incident starts)PostgreSQL
WITH gaps AS (
  SELECT
    service_name,
    started_at,
    started_at - LAG(started_at) OVER (
      PARTITION BY service_name ORDER BY started_at
    ) AS gap
  FROM incidents
  WHERE environment = 'production'
    AND severity IN ('sev1', 'sev2')
)
SELECT
  service_name,
  date_trunc('quarter', started_at) AS quarter,
  COUNT(gap) AS failure_gaps,
  AVG(EXTRACT(EPOCH FROM gap)) / 3600 AS mtbf_hours,
  percentile_cont(0.5) WITHIN GROUP (
    ORDER BY EXTRACT(EPOCH FROM gap)
  ) / 3600 AS median_between_failures_hours
FROM gaps
WHERE gap IS NOT NULL
GROUP BY 1, 2
ORDER BY 1, 2;
MTBF, MTTR, and availability in one rollupPostgreSQL
WITH rollup AS (
  SELECT
    service_name,
    COUNT(*) AS failures,
    SUM(EXTRACT(EPOCH FROM (resolved_at - started_at))) AS downtime_s
  FROM incidents
  WHERE resolved_at IS NOT NULL
    AND environment = 'production'
    AND severity IN ('sev1', 'sev2')
    AND started_at >= CURRENT_DATE - INTERVAL '90 days'
  GROUP BY service_name
)
SELECT
  service_name,
  failures,
  -- 7,776,000 s = the 90-day window
  ROUND((7776000 - downtime_s) / failures / 3600) AS mtbf_hours,
  ROUND(downtime_s / failures / 60) AS mttr_minutes,
  ROUND(100.0 * (7776000 - downtime_s) / 7776000, 3) AS availability_pct
FROM rollup
ORDER BY mtbf_hours ASC;

Pitfalls

Averaging two gaps and calling it a trend.→ Three incidents a quarter means two data points. Show the failure count on every MTBF card, prefer rolling six-month windows, and report the median gap next to the mean.
Letting the failure definition drift.→ Adding a noisy alert source or reclassifying severities changes MTBF without reliability changing. Freeze the qualifying rule in the model and version it when it moves.
Comparing MTBF across services with different definitions.→ A service that files a Sev-2 for every degradation will always look worse than one that saves incidents for outages. Normalize the rule before ranking.
Reading MTBF without MTTR.→ A 60-day MTBF with 8-hour recoveries can deliver worse availability than a 20-day MTBF with 5-minute recoveries. Always show the pair — and the derived availability — together.

Where this metric applies

Metrics

Dashboards

FAQ

What is the difference between MTBF and MTTR?
They're the two halves of the reliability cycle: MTBF is how long the system runs between failures; MTTR is how long it takes to bring it back once it fails. Together they determine availability — MTBF ÷ (MTBF + MTTR) — which is why the two belong in the same rollup query and on the same incident response dashboard. A team can raise availability by failing less often (MTBF up) or recovering faster (MTTR down), and the split tells you which lever is actually moving.
MTBF or MTTF — which one applies?
MTBF is for repairable systems: the service fails, gets fixed, and runs again, so there's a meaningful "between." MTTF (mean time to failure) is for non-repairable units — a disk that fails once and gets replaced — measuring lifespan rather than cycle time. Software services are repairable, so MTBF is the right frame; MTTF shows up when you're trending hardware fleets or battery-style components. Mixing the two mostly produces confusion about whether repair time is inside or outside the measurement.
What counts as a failure?
Whatever your written rule says — and the rule matters more than the math. A common baseline is Sev-1/Sev-2 incidents in production: real service degradation, not every page. If one team logs a failure per blip and another only for outages, their MTBF numbers aren't comparable, and adding a noisy alert source can halve MTBF overnight without reliability changing at all. Encode the severity filter in the model, keep it aligned with the incident count definition, and note that pages that led nowhere belong in the alert noise rate instead.
Why does our MTBF jump around so much?
Small samples. A service with three incidents a quarter has two gaps to average — one long quiet stretch doubles MTBF, one bad week halves it. Neither is a trend. Use longer windows (rolling six months rather than monthly), report the median gap next to the mean as in the SQL above, and show the failure count on every card so readers can see how thin the data is. For low-incident services, the honest statement is often "two failures in 90 days" — a plain count — rather than a mean dressed up as one.
How do you track MTBF in Metabase?
Sync incidents from PagerDuty, incident.io, or Datadog into a SQL database with started_at, resolved_at, service_name, and severity. Compute gaps between consecutive incident starts with LAG() per service, average them per quarter, and build one rollup that shows MTBF, MTTR, and derived availability side by side. Pin the trend to a MTBF dashboard and the long view to incident response trends.