HAProxy SslFrontendKeyRate: the handshake rate that drives CPU cost

SslFrontendKeyRate is the number of new (non-resumed) TLS handshakes per second across your HAProxy frontends. Because full TLS handshakes are the most CPU-intensive operation HAProxy performs, this metric is effectively the CPU cost of your TLS traffic expressed as a rate.

Operators usually look for this metric in two situations: HAProxy CPU is climbing and they need to know whether TLS is the cause, or they are doing capacity planning and need a defensible number for “how many handshakes per second can this box absorb.” Both depend on understanding what the metric counts, where it comes from, and what breaks it.

What it is and why it matters

When a client opens a TLS connection to an SSL-terminated frontend, one of two things happens:

  • Full handshake. Certificate validation, key exchange, asymmetric crypto. Expensive on the HAProxy side, burning real CPU per connection.
  • Session resumption. The client presents a session ID or ticket from a previous connection, HAProxy validates it against its session cache, and the asymmetric work is skipped. Cheap.

SslFrontendKeyRate counts only the first kind: new keys established per second. Resumed sessions do not increment it. SslRate counts all TLS sessions per second including resumed ones, so the gap between SslRate and SslFrontendKeyRate tells you how much of your TLS load is being handled cheaply.

An example of the gap: a frontend showing SslRate of 10378 with SslFrontendKeyRate of 2361, SslFrontendSessionReuse_pct at 77, and Idle_pct at 42 has roughly three quarters of TLS connections resuming and avoiding full handshake cost. If resumption broke and all 10378 sessions per second became full handshakes, the full-handshake load would rise more than fourfold and Idle_pct would collapse.

Two naming gotchas:

  • The field is SslFrontendKeyRate, exactly. There is no SslKeyRate; scripts written against the wrong name silently grep nothing.
  • It exists only in show info, not in the show stat CSV output. The HTTP stats page exposes only show stat data, so this metric never appears there. Any pipeline that only scrapes the CSV or the stats web UI is blind to it.

How it works

HAProxy’s SSL engine consults the session cache or ticket state on every incoming TLS connection. When the cache lookup misses or the client presents nothing to resume, the engine performs a full handshake and the new-key counter increments. show info reports this as a rate:

# Collect the TLS handshake signals from show info
echo "show info" | socat unix-connect:/var/run/haproxy.sock stdio | grep -E "^(SslRate|SslFrontendKeyRate|SslFrontendMaxKeyRate|SslFrontendSessionReuse_pct|SslBackendKeyRate|SslCacheLookups|SslCacheMisses|Idle_pct):"

Adjust the socket path for your install (/run/haproxy/admin.sock is another common location).

The related fields that make the metric interpretable:

FieldWhat it is
SslFrontendKeyRateNew frontend TLS handshakes per second. The CPU cost signal.
SslFrontendMaxKeyRatePeak value observed since process start. Useful for spotting bursts you missed.
SslRateTotal TLS sessions per second, resumed plus new. Compare against key rate for resumption share.
SslFrontendSessionReuse_pctPercentage of frontend TLS sessions resumed. The inverse of your full-handshake share.
SslCacheLookups / SslCacheMissesCumulative session cache counters. Hit rate = (Lookups - Misses) / Lookups. There is no SslCacheHits field; you compute it.
SslBackendKeyRateNew handshakes per second to backends (when server ... ssl is in use). The same CPU cost logic applies on the server side.
Idle_pctPercentage of time the event loop waits in poll(). The inverse proxy for HAProxy CPU saturation.

The core relationship: as SslFrontendKeyRate rises, Idle_pct falls proportionally. A rising key rate with a steady Idle_pct means you have headroom. A rising key rate with Idle_pct trending toward 20 percent means you are consuming your safety margin. Idle_pct below roughly 5 percent means the event loop is saturated and new connections will stall in handshake.

flowchart LR
    A[New TLS connections] --> B{Session resumable?}
    B -- yes --> C[Session cache hit]
    C --> D[Resumed session - low CPU]
    B -- no --> E[Full handshake]
    E --> F[SslFrontendKeyRate rises]
    F --> G[CPU consumed by crypto]
    G --> H[Idle_pct falls]
    H --> I[Handshake latency and stalls]
    C -.->|cache broken or flushed| E

Where it shows up in production

TLS CPU exhaustion is a first-class failure archetype. Under a high rate of new, non-resumed TLS connections, CPU saturates on handshakes. Throughput drops and latency spikes, but HAProxy does not crash; it just cannot complete handshakes fast enough. The composite pattern: SslFrontendKeyRate spiking well above baseline, Idle_pct dropping toward zero, session rate elevated, and backend connect time (ctime) rising because the event loop is too busy to establish backend connections promptly. A distinguishing feature is that backends are healthy throughout: rtime stays normal, errors stay low. The bottleneck is admission, not the application.

Broken session resumption is the common root cause. High SslFrontendKeyRate with a low cache hit ratio means every connection is paying full price. Causes include:

  • Session cache too small or disabled (tune.ssl.cachesize set to 0 disables it entirely, which some operators do deliberately for mTLS scenarios)
  • Clients that genuinely cannot resume: very diverse client populations, mobile fleets, one-shot scanners. Low reuse is normal for some workloads; the signal is a drop from your baseline
  • TLS library or version bugs that break resumption in specific releases. If SslFrontendSessionReuse_pct collapses with no config change, check the changelog for your exact version.
  • no-tls-tickets on the bind line disabling ticket-based resumption

Reloads reset everything. SslFrontendKeyRate and the cache counters are process-lifetime values; they reset on every reload. Worse, the in-process session cache is invalidated on reload, so every existing client that reconnects must do a full handshake. Expect a key-rate spike after every reload. Sharing ticket keys on disk across processes (tls-ticket-keys) mitigates the ticket path, but the cache spike still happens. If you reload frequently (dynamic service discovery, ingress controller), you are paying a full-handshake tax on a schedule, and your monitoring sees counter discontinuities on top of it.

The busy-polling caveat. Idle_pct is your inverse CPU proxy only when the event loop actually idles. With busy-polling enabled, Idle_pct sits near zero by design and tells you nothing. In that mode, use show activity run-queue depth or system CPU alongside SslFrontendKeyRate.

Multi-process mode. In nbproc deployments, each process has its own SSL session cache and its own key-rate counter. Resumption across processes is not shared, and per-process rates must be summed to get the fleet picture.

Tradeoffs and when this matters

The metric matters most in three operational contexts:

  • TLS capacity planning. Full handshakes per second is the resource you are actually provisioning for, not total sessions. Trend SslFrontendKeyRate at daily peak, pair it with Idle_pct at the same moment, and plan upgrades when peak Idle_pct drops below roughly 30 percent. SslFrontendMaxKeyRate tells you the worst burst the process has seen since start, which is the number your headroom must absorb.
  • Diagnosing a CPU climb. When HAProxy CPU rises, the first fork in the road is “TLS or not TLS.” SslFrontendKeyRate answers it in one command. If the key rate tracks the CPU curve, you are in the TLS domain and the next question is resumption health. If the key rate is flat while CPU climbs, look elsewhere: ACL evaluation, compression, Lua.
  • Attack and anomaly detection. Renegotiation abuse, handshake-flooding DDoS, and massive surges of unique clients all show up as key-rate excursions before they show up as 5xx. A key rate far above baseline with normal request rates is suspicious by itself.

One honest limitation: the exact sampling window for the rate is not documented. Treat it as a short-window gauge, not a precisely averaged rate, and trend it through a monitoring system rather than trusting single samples.

Signals to watch in production

SignalWhy it mattersWarning sign
SslFrontendKeyRateDirect measure of full-handshake CPU costTrending toward tested ceiling; spikes without matching traffic growth
SslFrontendMaxKeyRateWorst burst since process startFar above your planned headroom
SslRate vs SslFrontendKeyRateGap shows how much load resumption absorbsGap closing: resumption share falling
SslFrontendSessionReuse_pctPercentage of sessions avoiding full handshakesDeclining from baseline, or near zero unexpectedly
SslCacheLookups / SslCacheMissesComputed cache hit ratioMiss rate above 50% sustained past the post-reload window
Idle_pctEvent loop headroom (invalid with busy-polling)Below 20% sustained; below 5% is saturation
SslBackendKeyRateHandshake cost to TLS backendsRising when backend connection reuse should be stable; often pairs with a broken http-reuse
Uptime_secDetects reloads that reset counters and flush the cacheDrops explain key-rate spikes and counter discontinuities

A practical alerting shape: page when SslFrontendKeyRate is well above baseline or tested ceiling AND Idle_pct is under 5 percent (or, with busy-polling, show activity run-queue is rising) AND real traffic is degrading, sustained for a couple of minutes past the cold-start window. Ticket when the cache miss rate stays above 50 percent beyond the post-reload transient. Track everything else as baseline.

How Netdata helps

  • Netdata collects show info continuously, so SslFrontendKeyRate, SslRate, and the cache counters become time series instead of point-in-time socket dumps. That matters for a metric that is invisible in the CSV stats and the HTTP stats page.
  • Plotting SslFrontendKeyRate against Idle_pct on one dashboard makes the proportionality directly visible; divergence between the two is itself a diagnostic.
  • Counter resets on reload are handled as discontinuities rather than phantom drops, so post-reload handshake storms are readable instead of alarming.
  • Correlating SslFrontendSessionReuse_pct with the computed cache hit ratio lets you catch resumption regressions, the slow-failing case where CPU cost per connection rises for weeks before Idle_pct ever alerts.
  • Per-instance baselines make key-rate anomalies stand out: a burst that is normal at peak but anomalous at 4 AM is obvious on a trended chart.