Many developers who tuned values like maximumPoolSize using the HikariCP tuning guide have probably run into this problem: you can’t tell whether that value is actually sufficient for production traffic at the moment you set it. This article explains how to visualize the metrics HikariCP exposes to Micrometer using Actuator/Prometheus, and how to detect signs of pool exhaustion with thresholds and alerts before errors actually occur.
Logs alone won’t catch the warning signs of exhaustion
Error logs like Failed to validate connection only appear after the pool has actually been exhausted. By the time you notice, the impact has already happened.
Moreover, while the pool is approaching exhaustion, the number of waiting threads increases and responses simply get slower — often without throwing any exception at all. If you rely on error logs alone, you’ll miss this early warning stage entirely.
Mapping key metrics to tuning values
HikariCP exposes just under 10 metrics to Micrometer. Let’s look at them in their Prometheus-format names (where dots become underscores), alongside how they correspond to the settings you decided on in the tuning guide.
hikaricp_connections_activeis the number of connections currently in usehikaricp_connections_idleis the number of idle, available connections, corresponding to the current value ofminimumIdle. If it keeps trending toward zero, that’s a sign of approaching exhaustionhikaricp_connections_pendingis the number of threads waiting because they couldn’t acquire a connection — this is the most important indicator for detecting exhaustionhikaricp_connections_maxis simply the current value ofmaximumPoolSize; its ratio withactivegives you the utilization ratehikaricp_connections_acquire_secondsis the wait time to acquire a connection (since it’s a Timer type, it decomposes into multiple series)hikaricp_connections_timeout_totalis the count of acquisition failures that exceededconnectionTimeout
Configuration values represent “intent,” while metrics represent “actual state.” Only by comparing both can you tell whether your tuning is actually working.
Enabling the Prometheus endpoint in application.yml
First, add the dependencies.
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("io.micrometer:micrometer-registry-prometheus")
Next, expose the endpoint. management.metrics.enable.hikaricp defaults to true, so no additional configuration is needed there.
management:
endpoints:
web:
exposure:
include: health,metrics,prometheus
After starting the application, verify it:
curl -s localhost:8080/actuator/prometheus | grep hikaricp_connections
If you see output with the label pool="HikariPool-1", you’re good to go. This is the auto-generated name used when pool-name isn’t configured, so if you’ve set it explicitly, substitute that value in the queries that follow.
Visualizing signs of exhaustion with Prometheus
Judging based on instantaneous values alone increases false positives, so the key is to look at sustained duration. You can get the utilization rate with this query:
hikaricp_connections_active{pool="HikariPool-1"}
/ hikaricp_connections_max{pool="HikariPool-1"}
If it stays at 80% or higher for 5 minutes or more, that’s a danger zone. Use min_over_time to judge sustained pending counts.
min_over_time(hikaricp_connections_pending{pool="HikariPool-1"}[5m]) > 0
Since pending should normally be zero, even a one-minute stretch above zero deserves attention. In Grafana, placing a utilization gauge next to a pending time series makes the trend immediately visible. For the setup itself, refer to the Spring Boot Observability setup guide.
Designing alert rules in Prometheus
What we’re defining here are Prometheus-side “alert rules” (rule_files). The syntax differs from the Alertmanager configuration file (alertmanager.yml), so pasting this directly into the wrong file will cause a parse error.
groups:
- name: hikaricp
rules:
- alert: HikariPoolPendingThreads
expr: hikaricp_connections_pending{pool="HikariPool-1"} > 0
for: 1m
labels:
severity: critical
annotations:
summary: 'HikariCP connection waiting is occurring'
For a utilization-based rule, rewrite the expr and add severity: warning to set up a two-tier operation. The for clause is essential to avoid triggering on a momentary spike.
Notification is Alertmanager’s job. By splitting routing destinations based on severity, you can send critical alerts immediately.
route:
receiver: default-mail
routes:
- matchers: [severity = "critical"]
receiver: slack-critical
receivers:
- name: default-mail
email_configs: [{to: '[email protected]'}]
- name: slack-critical
slack_configs: [{channel: '#alerts-critical'}]
When a critical alert fires, don’t just reconsider the pool size — also suspect slow queries or connection leaks.
Summary
Tuning alone doesn’t tell you whether it’s actually sufficient in production. By mapping configuration values to metrics — like maximumPoolSize to hikaricp_connections_max — and setting up alerts for pending occurrences or sustained high utilization, you can respond before errors actually occur.
If you haven’t tuned yet, we recommend reading the HikariCP tuning guide first; if you’re unsure about Actuator, check out Getting Started with Spring Boot Actuator. If you’re already seeing errors, the guide to handling Failed to validate connection can help, and if your database’s max_connections is the bottleneck, see the article on Kubernetes replica scaling.