Glossary
Glossary

p95 Latency: Percentiles Explained, With SQL and PromQL

By Sazabi Team

Last verified on Nov 8, 2026.

An average latency answers the wrong question. It tells you the center of a pile of numbers, and a latency pile has a long tail. Users do not experience the center: they experience their own request, which is sometimes the slow one. Percentiles describe the distribution instead of collapsing it.

What a Percentile Is

The pXX value is the number that XX% of observations are at or below. Take the observed durations for a window, sort them, and read off the value at that position.

  • p50 (median): half of requests are faster. This is the typical request.
  • p95: 95% are faster. One in twenty is slower.
  • p99: 99% are faster. One in a hundred is slower.

Google's SRE book says the same: high percentiles such as the 99th or 99.9th show a plausible worst case, while the 50th percentile emphasizes the typical case. It adds that the higher the variance in response times, the more long-tail behavior affects the typical user experience, an effect made worse by queuing at high load. Google says it generally prefers percentiles to the mean.

Why the Average Fails: A Worked Example

Take 100 requests in a window: 94 take 100 ms and 6 take 5,000 ms.

StatisticValue
Mean394 ms
p50100 ms
p955,000 ms
p995,000 ms

The mean of 394 ms matches no request. Nobody had a 394 ms experience. The p50 says most users are fine, and the p95 says one in twenty is waiting five seconds. Alerting on the mean would show a modest bump and miss the problem. The SRE book makes the same point with a day's graph: the average stays flat while tail latency changes a lot.

Percentiles also vary in meaning with sample size. With only 20 requests in a window, p95 is close to the slowest request, so it is noisy. Use windows large enough to hold enough requests for the percentile you want, and show the request count beside the chart.

Calculating p95 Latency from Logs

If your request logs hold a duration, SQL can compute percentiles directly. PostgreSQL's percentile_cont takes a fraction and an ordering, and interpolates between adjacent values when the position falls between two requests. It works on numbers and on intervals:

SELECT route,
       count(*) AS requests,
       percentile_cont(0.50) WITHIN GROUP (ORDER BY duration_ms) AS p50_ms,
       percentile_cont(0.95) WITHIN GROUP (ORDER BY duration_ms) AS p95_ms,
       percentile_cont(0.99) WITHIN GROUP (ORDER BY duration_ms) AS p99_ms
FROM request_logs
WHERE ts >= now() - interval '1 hour'
  AND status < 500
GROUP BY route
ORDER BY p95_ms DESC;

Decisions that change the answer:

  • Which requests. Excluding errors, as above, measures how fast successful requests are. Include them if fast failures should count as good.
  • Which time window. A p95 per minute is volatile. A p95 per hour hides spikes.
  • Which dimension. A single global p95 is dominated by your busiest route. Split by route, region, or customer tier.
  • Where the timer starts and stops. Server-side time misses time in queues, proxies, and the network. Client-side or load balancer time sees more.

Approximating Percentiles with Histograms

Metrics systems rarely keep every request. Prometheus histograms count observations in buckets and estimate the percentile from them:

histogram_quantile(0.95, sum by (le) (rate(http_request_duration_seconds_bucket[5m])))

Two cautions come straight from Prometheus's documentation:

  • The estimate is only as good as the buckets. For classic histograms the error is limited by the width of the bucket the quantile lands in. Its example: with almost every request near 320 ms and a bucket spanning 300 to 450 ms, the estimated p95 is 443 ms, far from the true value close to 320 ms.
  • Do not average percentiles. Summaries calculate quantiles inside each process and cannot be aggregated, so averaging the 0.95 series from several instances is labeled "BAD". Histograms sum cleanly because bucket counts are additive.

The same logic applies in a SQL or log-analytics pipeline. Merge raw counts or buckets across hosts, then compute the percentile once. Never take a percentile of per-host percentiles.

Turning Percentiles into Targets

A percentile becomes an SLI once you attach a threshold: "the share of requests faster than 300 ms". That ratio form is easier to combine and alert on than the percentile value, because it is a fraction of good events. An SLO then sets the target, such as 99% under 300 ms over 28 days.

What to Watch

  • p95 up while p50 is flat. A subset of requests is slow: one dependency, one tenant, or one route. See tail latency for the p99 version of this, including how to compare p99 with the median.
  • Both rise together. The whole service slowed, which points to load or a shared resource. See latency spikes.
  • Slow creep over days. A gradual rise that no single alert catches is covered under latency drift.

Percentiles are the "latency" in the golden signals. They are also the input to Apdex scores, a different way to summarize the same distribution: see Apdex.

Frequently Asked Questions

What does p95 latency mean?

The response time that 95% of requests are at or below. If p95 is 800 ms, one request in twenty took longer than that.

Why use p95 instead of average latency?

An average hides the slow tail. Google's SRE book notes that most requests can be fast while a long tail is much slower, and the mean shows nothing wrong. Percentiles show the shape.

What is the difference between p50, p95, and p99?

p50 is the median, the typical experience. p95 and p99 show how bad the slow requests get. The SRE book says high percentiles show a plausible worst case and the median emphasizes the typical case.

Can I average p95 values across servers?

No. Percentiles from separate instances cannot be combined by averaging. Prometheus calls this approach wrong for quantiles and recommends histograms, which can be summed before the quantile is calculated.

Sources

  1. Percentiles describe the shape of the distribution: high percentiles show plausible worst case and the median shows the typical case; averaging latencies hides a slow tail; Google prefers percentiles to the mean (accessed Nov 8, 2026)
  2. percentile_cont computes a continuous percentile within an ordered set and interpolates between adjacent values, for double precision and interval inputs (accessed Nov 8, 2026)
  3. Quantiles estimated from classic histograms have error limited by bucket width; quantiles from summaries cannot be aggregated across instances; histograms can be (accessed Nov 8, 2026)
  4. histogram_quantile calculates a quantile from classic or native histograms, with rate() and sum by (le) for aggregation (accessed Nov 8, 2026)