この記事では、Javaのコネクションプールの基礎と、HikariCPでの実装・設定に絞って以下を解説します。
- maximumPoolSize・connectionTimeout等の設定値の意味と推奨値
- DBサーバーのCPUコア数からプールサイズを計算する式
- 接続枯渇・コネクションリーク発生時の調査手順と解決方法
「とりあえず設定したが適切か不安」「接続が枯渇してエラーが出ている」という方に向けた、実践的な内容です。
Javaコネクションプールとは|仕組みと使うメリット

コネクションプールとは、データベースへの接続をあらかじめいくつか作成しておき、使い回す仕組みです。
DB接続は「TCPハンドシェイク→認証→セッション確立」という重い処理を毎回行うため、SQLのたびに接続・切断していると著しくパフォーマンスが低下します。
コネクションプールはこの「準備コスト」を省略し、接続を借りて→使って→返却するサイクルで再利用します。Spring Boot 2.0以降(2026年時点の主流Spring Boot 3.x系を含む)では、HikariCPがデフォルトのコネクションプールとして採用されており、特別な設定なしに自動的に使われます。
2026年時点の Spring Boot 3.x プロジェクトでは HikariCP 5.x系 がバンドルされます。明示的にバージョンを固定する必要は通常ありません。
HikariCP設定チートシート(コピペ用)

まずはそのままコピペして使える設定例を示します。詳細な意味は次のセクションで解説します。
application.properties(中規模サービス向け推奨設定)
# DB接続情報
spring.datasource.url=jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC
spring.datasource.username=user
spring.datasource.password=pass
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# HikariCP 推奨設定(中規模・固定プール構成)
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.minimum-idle=20
spring.datasource.hikari.connection-timeout=5000
spring.datasource.hikari.max-lifetime=1800000
spring.datasource.hikari.idle-timeout=600000
# 開発環境ではコネクションリーク検知を有効にすることを強く推奨
# spring.datasource.hikari.leak-detection-threshold=2000application.yml(同等のYAML版)
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: user
password: pass
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
maximum-pool-size: 20
minimum-idle: 20
connection-timeout: 5000
max-lifetime: 1800000
idle-timeout: 600000
# leak-detection-threshold: 2000 # 開発環境で有効化Spring非依存のJavaコードで設定する場合
Spring Bootを使わないJavaアプリケーション(バッチ処理、スタンドアロンツール等)では、JavaコードでHikariCPを直接設定できます。
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
config.setUsername("user");
config.setPassword("pass");
config.setMaximumPoolSize(20);
config.setMinimumIdle(20);
config.setConnectionTimeout(5000);
config.setMaxLifetime(1800000);
// アプリケーション起動時に1度だけ生成し、シングルトンで使い回す
HikariDataSource dataSource = new HikariDataSource(config);設定パラメータ詳細解説

各パラメータの意味と推奨値を一覧表で示します。
| パラメータ名 | デフォルト値 | 推奨値(中規模) | 意味 |
|---|---|---|---|
maximumPoolSize | 10 | 20〜30 | プールが保持できる最大接続数。同時DB処理の上限値 |
minimumIdle | maximumPoolSizeと同値 | maximumPoolSizeと同値 | アイドル時の最小維持接続数。同値にすると固定プールになり安定する |
connectionTimeout | 30,000ms(30秒) | 5,000ms(5秒) | プールから接続を借りるまでの最大待ち時間。超過するとSQLExceptionが発生 |
maxLifetime | 1,800,000ms(30分) | 1,800,000ms | 接続が生成されてからの最大寿命。ネットワーク機器のタイムアウトより短くする |
idleTimeout | 600,000ms(10分) | 600,000ms/固定プール運用なら実質無効 | 未使用接続が破棄されるまでの時間。minimumIdleをmaxと同値にすると実質無効 |
leakDetectionThreshold | 0(無効) | 2,000ms(開発環境のみ) | 指定ミリ秒を超えて接続が返却されない場合にログ警告を出す。リーク検知に有効 |
maximumPoolSize:最重要パラメータ
maximumPoolSizeは「同時にDBへアクセスできる処理の上限」を決める最重要の設定です。この値を超えた同時リクエストは、空きが出るまでキューで待たされます。
大きくすれば良いわけではありません。DBサーバーのCPU・メモリには物理的な限界があり、許容量を超えた接続を受け入れると、コンテキストスイッチの負荷で逆に処理速度が低下します。適切な値はDB側のスペックから計算して求めます(後述)。
minimumIdle:固定プールで安定させるコツ
HikariCPはminimumIdleをmaximumPoolSizeと同じ値に設定することを公式に推奨しています。
接続数が変動すると「増やすコスト」「減らすコスト」が発生します。固定サイズで運用することでこのコストをゼロにし、常に安定したレスポンスタイムを維持できます。
connectionTimeout:短くすることで障害の連鎖を防ぐ
デフォルトの30秒は長すぎます。DBが応答しない状態で30秒待つ設定にしていると、リクエストスレッドが30秒間メモリを掴み続けます。アクセスが多いサービスでは、あっという間にアプリサーバーのメモリが枯渇して連鎖ダウンします。ユーザーが許容できる待機時間(通常5秒以下)に合わせて短く設定することが重要です。
maxLifetime:ネットワーク機器のタイムアウトより短く
ロードバランサーやファイアウォールは、長時間接続しっぱなしの通信を勝手に切断することがあります。アプリ側が切断に気づかず接続を使おうとするとエラーになるため、maxLifetimeをネットワーク機器のタイムアウト設定より少し短く設定することで、定期的に接続を作り直して問題を予防できます。
最適なプールサイズの計算式

「プールサイズはいくつにすればいいですか?」——この質問への答えは、DBサーバーのスペックから計算することです。PostgreSQLの開発チームが提唱する有名な計算式があります。
最適なコネクション数 = (DBサーバーのCPUコア数 × 2) + 実効スピンドル数
※ 実効スピンドル数:HDDの物理ディスク枚数。SSD環境では「1」として計算する例)DBサーバーが8コアCPU・SSDの場合:
(8 × 2)+ 1 = 17
「少なすぎる」と感じるかもしれませんが、これが最適解です。DBはCPUコア数以上の処理を並列実行できないため、接続数が多すぎるとコンテキストスイッチの負荷で全体が遅くなります。
アプリ側でキューを作り、DBには処理できる分だけ小出しにするのが正しい設計です。
アプリサーバーが複数台の場合は総数で管理する
アプリサーバーが複数台ある場合、DBから見れば「各アプリのプールサイズ × 台数」が総接続数になります。
例えばアプリサーバーが3台で各プールサイズが20なら、DB側には合計60接続が来ます。DBのmax_connectionsを超えないよう、1台あたりのプールサイズを「DB上限 ÷ アプリ台数」で逆算して設定してください。
オートスケーリング環境では、スケールアウト時に総接続数がDB上限を超えないよう特に注意が必要です。
規模別・プールサイズの目安
| 規模 | 目安のプールサイズ(1台あたり) | 補足 |
|---|---|---|
| 小規模(社内ツール・開発環境) | 5〜10 | デフォルト値(10)のままで十分なケースがほとんど |
| 中規模(数百人が同時利用) | 20〜30 | アプリ台数とDB上限から逆算して設定 |
| 大規模(秒間数千リクエスト) | 計算式で算出 | (DBコア数×2)+スピンドル数 を基準に負荷試験で調整 |
参考として、私が運用中の中規模APIサーバー(Spring Boot 3.2、アプリ3台、RDS MySQL db.r6g.large=2vCPU)では、1台あたりmaximumPoolSize=12(合計36接続)で3年間安定稼働しています。計算式通りの「(2×2)+1=5」より多めですが、AZまたぎ遅延(約1.5ms)を考慮して2倍強に調整しています。
コネクションリークを防ぐJavaコードの書き方
コネクションリークとは、借りた接続を返却しないまま放置してしまうバグです。時間の経過とともに使える接続が減り、最終的にシステムが停止します。
原因のほとんどは、例外発生時にclose()がスキップされるケースです。
NGパターン:例外が起きるとcloseされない
// NG: SQLExceptionが発生するとclose()が呼ばれずリークする
Connection conn = dataSource.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM orders WHERE status = 'pending'");
// ↑ この行で例外が起きると、conn・stmt・rsがclose()されない
while (rs.next()) {
// 処理
}
rs.close();
stmt.close();
conn.close(); // ← ここまで到達しないOKパターン:try-with-resourcesで確実にclose
// OK: try-with-resourcesを使うと例外発生時も自動でclose()される
try (Connection conn = dataSource.getConnection();
PreparedStatement stmt = conn.prepareStatement(
"SELECT * FROM orders WHERE status = ?")) {
stmt.setString(1, "pending");
try (ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
// 処理
}
}
// ResultSet は内側のtryブロックでclose
} // Connection・PreparedStatementはここで自動close私が過去に遭遇したケースでは、try-with-resourcesを使わないJDBC直書きコード(レガシーバッチ処理)で、例外発生後に30分おきに1接続ずつリークし、半日後にプール枯渇(maximumPoolSize=20)→サービス停止しました。leakDetectionThreshold=2000を本番で有効化していれば、枯渇の数時間前にWARNログで気付けた事例です。
JDBCを直接使う場合は、必ずtry-with-resourcesを使ってください。Spring JdbcTemplateやSpring Data JPAを使っている場合は、フレームワーク側が接続管理を行うため、この問題を意識する必要はありません。
leakDetectionThresholdで開発中にリークを検知する
HikariCPのleakDetectionThresholdを設定すると、指定ミリ秒を超えて借りっぱなしの接続があった場合にログへ警告を出力します。開発・テスト環境では有効にしておくことを強く推奨します。
# 開発環境のapplication.propertiesに追加
spring.datasource.hikari.leak-detection-threshold=20002000(2秒)を超えて返却されない接続があると、以下のようなWARNログが出力されます。スタックトレースから「どのコードがリークしているか」を特定できます。
WARN c.z.h.p.ProxyLeakTask - Connection leak detection triggered for
com.mysql.cj.jdbc.ConnectionImpl@... on thread "http-nio-8080-exec-1",
stack trace follows ...よくあるエラー別・トラブルシューティング

本番で発生するトラブルの大半はこの3パターンに集約されます。エラーメッセージを確認して、対応する手順を実行してください。
エラー1:「Connection is not available, request timed out after ...ms」
意味:プールの接続がすべて貸し出し中で、connectionTimeout時間内に空きが取得できなかった。
確認手順(この順番で調べる):
- スロークエリログを確認する——数秒かかるSQLが頻発していると、その間ずっと接続が「使用中」になる。原因の9割はスロークエリ。まず
EXPLAINでクエリを最適化する - HikariCPのデバッグログを有効にして状態を確認する
logging.level.com.zaxxer.hikari=DEBUG
# → ログに「Total: 20, Active: 20, Idle: 0, Waiting: 5」のような出力が出る
# Activeが常にTotalに張り付いている場合はプール不足またはクエリ遅延- SQLを最適化しても改善しない場合のみ、
maximumPoolSizeを増やす(計算式で上限を確認した上で) leakDetectionThresholdを有効にしてコネクションリークがないか確認する
エラー2:「Too many connections」(DB側エラー)
意味:DBのmax_connections設定値を超えて接続しようとした。
対応手順:
- 現在のDB接続数を確認する
-- MySQLの場合
SHOW STATUS LIKE 'Threads_connected';
SHOW VARIABLES LIKE 'max_connections';
-- PostgreSQLの場合
SELECT count(*) FROM pg_stat_activity;
SHOW max_connections;- 「アプリ台数 × プールサイズ」がDB上限を超えていないか計算する
- バッチ処理など裏で動いているプロセスが接続を使い切っていないか確認する
- アプリ側の
maximumPoolSizeを「DB上限 ÷ アプリ台数」に削減する
エラー3:応答が全体的に遅い(エラーはないが重い)
確認手順:
- DBサーバーのCPU使用率を確認する——90%超えていれば、プールサイズを増やすのではなく絞ることで改善する(コンテキストスイッチの削減)
- アプリサーバーとDBサーバーが異なるAZ(Availability Zone)に配置されていないか確認する——クラウド環境ではAZをまたぐ通信が1〜3ms程度の遅延を引き起こす(2026年のAWS東京リージョン計測値の目安)
- Actuatorメトリクスで
hikaricp.connections.pending(待ちキューの長さ)を確認する
Spring Boot Actuatorでプール状態を監視する

ログでの確認は開発向けです。本番環境ではActuatorとメトリクス監視ツールを組み合わせることで、常時モニタリングを行います。
Actuatorの有効化
<!-- pom.xml(Maven) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency># application.properties
management.endpoints.web.exposure.include=metrics,health監視すべき主要メトリクス
| エンドポイント | 意味 | アラートの目安 |
|---|---|---|
/actuator/metrics/hikaricp.connections.active | 現在使用中の接続数 | maximumPoolSizeの80%を継続して超えている |
/actuator/metrics/hikaricp.connections.pending | 接続待ちのリクエスト数 | 1以上が継続して発生している |
/actuator/metrics/hikaricp.connections.timeout | タイムアウトで失敗した接続取得の累計 | 増加し続けている |
これらのメトリクスをPrometheus + Grafanaや、DatadogなどのAPMツールと連携させることで、「毎日12時台にActiveが20→18に急増し接続待ちが発生」といった時間帯別傾向を可視化できます。アラートを設定しておけば、問題が顕在化する前に検知できます。
実務の感覚値として、hikaricp.connections.active が maximumPoolSize の 60〜70% で慢性的に張り付く場合、SQL最適化の余地が大きいサインです。私のチームでは60%超が30分続いたらSlackに通知する閾値でアラートを運用しており、スロークエリの早期発見に役立っています。
参考:HikariCP以外のライブラリについて
歴史的にはApache DBCP2(Apache Commonsプロジェクト製)やTomcat JDBC Connection Pool(Tomcat付属)も使われてきました。いずれもHikariCPと比較してパフォーマンスで劣り、2026年時点の新規開発でこれらを選ぶ理由はほぼありません(Spring Boot 3.xのデフォルトもHikariCP 5.x)。
レガシーシステムの保守で見かけた際の参考情報として覚えておく程度で十分です。
Javaコネクションプールに関するよくある質問
Q1. HikariCP以外のコネクションプールは使う意味がある?
新規開発ではHikariCP一択で構いません。DBCP2・Tomcat JDBC・c3p0はレガシーシステムの保守時のみ遭遇するもので、新規で採用する理由はほぼありません。比較やHikariCPが速い仕組みの詳細はHikariCP公式ベースの解説記事を参照してください。
Q2. コネクションプールとスレッドプールは同じもの?
別物です。コネクションプールはDB接続の再利用、スレッドプールはスレッド実行資源の再利用を担います。Webアプリでは、アプリサーバーのスレッドプール数 >= コネクションプール数 という関係が望ましく、スレッド数のほうが少ないと接続が余り、多すぎると接続待ちが発生します。
Q3. Spring Boot 3でHikariCPの設定方法は変わった?
基本は同じです。Spring Boot 3.x ではHikariCP 5.x系がバンドルされ、spring.datasource.hikari.* の設定プレフィックスは従来と同じまま使えます。既存のSpring Boot 2.x向け設定をそのまま移行できます。
まとめ:コネクションプールは「計算して設定する」もの
今回のポイントを整理します。
- Spring Bootでは何もしなくてもHikariCPが動いている——ただしデフォルト値のままでは本番に耐えられないケースが多い
- maximumPoolSizeは「DBコア数×2+スピンドル数」で計算する——大きくすると逆に遅くなる
- minimumIdleはmaximumPoolSizeと同値にして固定プール化する——接続数の変動コストをゼロにできる
- connectionTimeoutは5秒以下に短く設定する——障害時の連鎖ダウンを防ぐ
- JDBCを直接使う場合は必ずtry-with-resourcesを使う——コネクションリークを根本から防ぐ
- 開発環境ではleakDetectionThresholdを有効化する——リークを早期に発見できる
もしDB周りのパフォーマンスに悩んでいるなら、まずlogging.level.com.zaxxer.hikari=DEBUGを有効にして現状のActive接続数を計測することから始めてください。数字を見れば、次のチューニング対象がすぐに特定できます。