Blog Post

Azure Database Support Blog
5 MIN READ

Generic Best Practices for HikariCP with Azure Database for PostgreSQL

Mohamed_Baioumy_MSFT's avatar
Jun 26, 2026

Author: Mohamed Baioumy
Technology: Azure Database for PostgreSQL (Flexible Server & Single Server)
Category: Connectivity | Performance | Application Design

Introduction

Connection pooling is a critical component of application performance when connecting to Azure Database for PostgreSQL. Creating a new PostgreSQL connection is an expensive operation that consumes CPU, memory, and networking resources. Reusing existing connections through a connection pool significantly reduces connection latency, improves throughput, and helps applications scale more efficiently.

Many Java applications use HikariCP, one of the most popular high-performance JDBC connection pools. While HikariCP provides excellent performance out of the box, improperly configured connection pool settings can lead to issues such as:

  • Connection pool exhaustion
  • Stale or invalid connections
  • Increased connection acquisition latency
  • Excessive connection creation and destruction
  • Database resource contention
  • Application timeouts

This article summarizes generic guidance and best practices for configuring HikariCP when working with Azure Database for PostgreSQL Flexible Server and Azure Database for PostgreSQL Single Server.

Understanding Key HikariCP Parameters

1. Maximum Lifetime (maxLifetime)

The maxLifetime property controls how long a connection can remain in the pool before HikariCP retires it and creates a new one.

Why It Matters

Connections can become stale over time due to:

  • Network interruptions
  • Infrastructure updates
  • Connection state changes
  • TCP idle behavior

Recycling connections periodically helps prevent applications from using long-lived connections that may no longer be healthy.

Recommended Practice

Avoid configuring the value too low.

When maxLifetime is set aggressively, HikariCP continuously destroys and recreates connections, resulting in:

  • Additional authentication overhead
  • Increased connection establishment latency
  • Higher CPU utilization
  • Reduced application throughput

A reasonable starting point is:

spring.datasource.hikari.maxLifetime=1800000

30 minutes (1,800,000 ms) is commonly used and aligns well with many production workloads. Depending on workload characteristics, values between 30 minutes and 1 hour are generally suitable

Avoid

maxLifetime=300000

(5 minutes)

This often causes unnecessary connection churn without providing additional benefits.

2. Minimum Idle Connections (minimumIdle)

The minimumIdle setting defines how many idle connections HikariCP should keep ready for immediate use.

Why It Matters

A pool with available idle connections can serve application requests immediately without waiting for new connections to be established.

However, maintaining too many idle connections consumes unnecessary database resources.

Recommended Practice

For most workloads:

minimumIdle = maximumPoolSize

Or

minimumIdle slightly lower than maximumPoolSize

This ensures sufficient connections are already available during traffic spikes while avoiding excessive connection creation delays.

Example

maximumPoolSize=20
minimumIdle=15

Avoid

maximumPoolSize=20
minimumIdle=20

only when the application experiences long periods of inactivity and conserving resources is more important than immediate responsiveness.

3. Idle Timeout (idleTimeout)

The idleTimeout property determines how long an unused connection remains in the pool before being removed.

Why It Matters

Connections that sit idle for extended periods consume resources on both:

  • The application server
  • Azure Database for PostgreSQL

However, removing idle connections too quickly causes the application to repeatedly establish new connections.

Recommended Practice

Keep the default value unless there is a specific requirement.

spring.datasource.hikari.idleTimeout=600000

which equals:

10 minutes (600,000 ms)

This setting provides a good balance between resource utilization and responsiveness. [Re: EXT: R...0040002947 | Outlook]

The timeout should also be comfortably longer than any expected short application idle periods.

Avoid

idleTimeout=10000

(10 seconds)

Such aggressive settings often result in unnecessary connection creation cycles.

4. Maximum Pool Size (maximumPoolSize)

This parameter determines the maximum number of concurrent database connections the application can maintain.

Why It Matters

This is often the most important HikariCP setting.

If the Pool Is Too Small

Applications may experience:

Connection is not available, request timed out

because all available connections are already in use. Similar scenarios have been observed during customer investigations involving Hikari pool exhaustion.

If the Pool Is Too Large

Applications can overwhelm the database server with excessive concurrent sessions, resulting in:

  • Connection contention
  • Increased context switching
  • Higher memory consumption
  • Reduced overall performance

Recommended Practice

Pool size should be based on:

  • Database compute configuration
  • CPU core count
  • Query execution duration
  • Application concurrency requirements
  • Workload characteristics

There is no universal value that fits every workload.

Start conservatively:

maximumPoolSize=10

or

maximumPoolSize=20

maximumPoolSize=20

and increase only after load testing demonstrates a need for additional concurrency.

Fixed-Size Pool Recommendation

For many production workloads, a fixed-size pool provides the simplest and most predictable behavior.

Configure:

maximumPoolSize=20
minimumIdle=20

or omit minimumIdle entirely so it defaults to maximumPoolSize. HikariCP commonly recommends maintaining a fixed-size pool for responsiveness during demand spikes.

Benefits

  • Faster connection acquisition
  • Predictable performance
  • Reduced connection creation latency
  • Better handling of traffic spikes

When using a small fixed-size pool, there is often little need to aggressively tune:

  • minimumIdle
  • idleTimeout

Instead, simply recycle connections using:

maxLifetime

maxLifetime

Additional Recommendations

Enable TCP Keepalive

One common cause of stale connections is network devices silently dropping inactive TCP sessions.

For PostgreSQL applications, consider enabling TCP keepalive:

tcpKeepAlive=true

tcpKeepAlive=true

The HikariCP project specifically recommends enabling TCP keepalive to prevent rare situations where pools can lose valid connections.

Monitor Connection Usage

Track:

  • Active connections
  • Idle connections
  • Connection acquisition time
  • Pool exhaustion events
  • Database connection counts

These metrics help identify whether pool sizing is appropriate.

Investigate Long-Running Queries

Connection pool problems are often symptoms rather than root causes.

A frequent scenario is:

  1. A query becomes slow.
  2. Connections remain occupied longer.
  3. The pool becomes exhausted.
  4. Applications start timing out.

When analyzing HikariCP issues, always review:

  • Query performance
  • Blocking situations
  • Database resource utilization
  • Application connection handling logic

Sample Production Configuration

spring.datasource.hikari.maximumPoolSize=20

spring.datasource.hikari.minimumIdle=15

spring.datasource.hikari.maxLifetime=1800000

spring.datasource.hikari.idleTimeout=600000

spring.datasource.hikari.connectionTimeout=30000

spring.datasource.hikari.keepaliveTime=60000

spring.datasource.hikari.maximumPoolSize=20
spring.datasource.hikari.minimumIdle=15
spring.datasource.hikari.maxLifetime=1800000
spring.datasource.hikari.idleTimeout=600000
spring.datasource.hikari.connectionTimeout=30000
spring.datasource.hikari.keepaliveTime=60000

This configuration provides a solid starting point for many Azure Database for PostgreSQL workloads and can be adjusted based on application-specific requirements.

a { text-decoration: none; color: #464feb; } tr th, tr td { border: 1px solid #e6e6e6; } tr th { background-color: #f5f5f5; }

Conclusion

HikariCP is extremely efficient when configured appropriately. The goal is not to maximize the number of connections, but rather to maintain a healthy balance between application responsiveness and database resource consumption.

As a general rule:

  1. Use a reasonable maxLifetime (30–60 minutes)
  2. Keep enough idle connections available for traffic spikes
  3. Avoid aggressive idleTimeout values
  4. Size the pool based on workload characteristics, not guesses
  5. Consider fixed-size pools for predictable performance
  6. Monitor connection usage and query performance regularly

By following these practices, applications connecting to Azure Database for PostgreSQL can achieve improved scalability, lower latency, and more reliable connectivity.

References

Connection pooling best practices - Azure Database for PostgreSQL

Performance best practices for using Azure Database for PostgreSQL – Connection Pooling

HikariCP Documentation and Pool Sizing Guidance

Published Jun 26, 2026
Version 1.0

2 Comments

  • subhashkv77's avatar
    subhashkv77
    Copper Contributor

    HI Mohamed_Baioumy_MSFT​

    Nice article.

    Any recommendations when using pgBouncer with Azure postgreSQL Flexible server (PostgreSQL 17) and HikariCP? we  see this error few times for an application in the pgbouncer log "closing because: client disconnect while server was not ready"
    spring.datasource.hikari.maximumPoolSize=300

    spring.datasource.hikari.minimumPoolSize=100

    • Mohamed_Baioumy_MSFT's avatar
      Mohamed_Baioumy_MSFT
      Icon for Microsoft rankMicrosoft

      Thank you for the feedback and for sharing the configuration.

      When PgBouncer is used together with HikariCP, it is important to avoid configuring two very large pooling layers. With maximumPoolSize=300 and minimumPoolSize=100, each application instance can maintain a substantial number of client connections to PgBouncer. If multiple application pods or instances use the same settings, the total client count can grow quickly.

      The PgBouncer message client disconnect while server was not ready generally indicates that the client disconnected while PgBouncer was still waiting for or preparing a PostgreSQL backend connection. By itself, it does not confirm a PostgreSQL server failure. It can occur when the application timeout is reached first, a request is cancelled, an instance is shutting down, or PgBouncer has clients waiting for available server connections.

      I would recommend starting with a significantly smaller HikariCP pool and sizing it from measured application concurrency rather than the database’s maximum connection capacity. As an initial test, you could reduce maximumPoolSize to a conservative range such as 20 to 50 per application instance and set minimumIdle much lower, for example 0 to 10. These are starting points only and should be validated through load testing and production metrics.

      Also, please calculate the aggregate pool across all instances:

      maximumPoolSize × application instances × data sources

      On the PgBouncer side, verify pool_mode, default_pool_size, max_client_conn, and query_wait_timeout. Azure’s built-in PgBouncer uses transaction pooling by default. Please also enable PgBouncer diagnostics and correlate the event timestamps with client_connections_waiting, active and idle server connections, total pooled connections, application connection-timeout errors, pod restarts, and long-running transactions.

      If client_connections_waiting increases during the events, this would indicate that clients are waiting for PostgreSQL backend capacity. If it remains at zero, the investigation should focus more on client timeout, cancellation, instance lifecycle, or transient connectivity.

      A possible test configuration could be:

      spring.datasource.hikari.maximumPoolSize=30

      spring.datasource.hikari.minimumIdle=5

      spring.datasource.hikari.connectionTimeout=30000

      The timeout value should be aligned with the application’s latency requirements and PgBouncer’s waiting behavior. I would avoid increasing pool sizes or timeouts before confirming where the wait occurs, as that can hide saturation and increase connection pressure.

      Azure references: