- Spring
Communications link failureの原因と直し方|MySQL
com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure は、MySQL Connector/J(MySQL の JDBC ドライバ)が、MySQL サーバーとの通信そのものに失敗したときに出るエラーです。 SQL の間違いやパスワードの間違いではなく、ネットワークか接続の状態に原因があります。
原因は大きく2つに分かれ、メッセージの2行目を見ればどちらかが分かります。
| 2行目のメッセージ | 状態 | 主な原因 |
|---|---|---|
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server. |
一度もつながっていない | MySQL が起動していない、ホスト名・ポートの間違い、bind-address、Docker の localhost、ファイアウォール |
The last packet successfully received from the server was 28,800,123 milliseconds ago. The last packet sent successfully to the server was ... |
つながっていたが途中で切れた | wait_timeout による切断、接続プールの設定、ネットワーク機器のタイムアウト、MySQL の再起動 |
The client was disconnected by the server because of inactivity. |
使っていない間にサーバーが切った(MySQL 8.0.24 以降) | wait_timeout・interactive_timeout |
この記事では、それぞれの原因を実際に起こし、出たメッセージと直し方を並べました。
確認環境:Ubuntu 24.04、MySQL 8.0.46、OpenJDK 21.0.10、Docker 29.4.3(確認日 2026年10月10日)。Connector/J のメッセージは、Connector/J 9.7.0 のソース(メッセージの定義とメッセージを組み立てる処理)で確認しました。下層のネットワークのエラーは、Java の Socket で同じ接続を試して再現しています。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Communications link failureの原因と直し方|MySQL」
メッセージの読み方
com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
at com.mysql.cj.jdbc.exceptions.SQLError.createCommunicationsException(...)
...
Caused by: com.mysql.cj.exceptions.CJCommunicationsException: Communications link failure
...
Caused by: java.net.ConnectException: Connection refused
| 部分 | 見るところ |
|---|---|
| 2行目 | 「has not received any packets」なら一度もつながっていない。「successfully received ... milliseconds ago」ならつながった後に切れた |
| ミリ秒の数字 | つながった後に切れた場合、最後に通信してからの時間。wait_timeout(既定 28800 秒=8時間)を超えていれば、サーバーが切った |
一番下の Caused by: |
本当の原因。ConnectException・SocketTimeoutException・UnknownHostException・SSLHandshakeException など |
Connector/J は、最後に通信した時刻とサーバーの wait_timeout を比べてメッセージを作ります。最後の通信から wait_timeout 以上たっていれば、2行目に続けて is longer than the server configured value of 'wait_timeout' という説明と、接続の有効性を使う前に確かめる・タイムアウトを延ばすといった対処の案が付きます。
一番下の Caused by で原因を分ける
同じ接続を Java の Socket で試すと、Caused by: に出る例外を再現できます。次のプログラムは、DB のホストとポートに TCP でつながるかだけを調べます(ドライバが無くても動くので、切り分けに便利です)。
import java.net.*;
/** DB のホスト・ポートに TCP でつながるかだけを調べる: java Probe.java ホスト ポート */
public class Probe {
public static void main(String[] a) throws Exception {
String host = a[0];
int port = Integer.parseInt(a[1]);
long t = System.currentTimeMillis();
try (Socket s = new Socket()) {
s.connect(new InetSocketAddress(host, port), 5000); // 5秒でタイムアウト
System.out.println("OK: " + s.getRemoteSocketAddress());
} catch (Exception e) {
System.out.println(e + " (" + (System.currentTimeMillis() - t) + " ms)");
}
}
}
$ java Probe.java localhost 3306
OK: localhost/127.0.0.1:3306
$ java Probe.java localhost 3307
java.net.ConnectException: Connection refused (7 ms)
$ java Probe.java 10.255.255.1 3306
java.net.SocketTimeoutException: Connect timed out (5008 ms)
$ java Probe.java db 3306
java.net.UnknownHostException: db (9 ms)
Caused by: |
意味 | 確認すること |
|---|---|---|
ConnectException: Connection refused |
相手のマシンには届いたが、そのポートで待ち受けていない | MySQL が起動しているか、ポート番号、bind-address(例2)、Docker の localhost(例3) |
SocketTimeoutException: Connect timed out |
相手から何も返ってこない | IP アドレス、ファイアウォール・セキュリティグループ、VPN |
UnknownHostException: db |
ホスト名を IP アドレスに変換できない | ホスト名の綴り、Docker のサービス名とネットワーク(例3) |
SSLHandshakeException: No appropriate protocol |
TLS のバージョンが合わない | 例5 |
EOFException: Can not read response from server |
つながっていた接続が相手側から切られた | 例4 |
Connection refused はすぐに返り、Connect timed out はタイムアウトの時間(上の例は5秒)だけ待たされます。画面が固まってから出るなら経路、すぐ出るならポートと見当を付けられます。
例1:MySQL が起動していない・ポートが違う
Caused by: java.net.ConnectException: Connection refused
| 確認 | Linux | Windows |
|---|---|---|
| MySQL が動いているか | systemctl status mysql(または mysqld) |
サービス一覧で「MySQL80」など |
| 待ち受けているポート | ss -ltn | grep 3306 |
netstat -ano | findstr 3306 |
| 接続URLのポート | jdbc:mysql://ホスト:3306/DB名 |
同じ |
ポートを変えている(3307 など)ことに気づかず、接続URLは 3306 のまま、というケースも多くあります。
例2:bind-address が 127.0.0.1 で、他のマシンからつながらない
MySQL の設定 bind-address が 127.0.0.1 だと、同じマシンの中からしか接続できません。Ubuntu の apt で入れた MySQL は、この設定になっています。
mysql> SHOW VARIABLES LIKE 'bind_address';
+---------------+-----------+
| bind_address | 127.0.0.1 |
+---------------+-----------+
$ ss -ltn | grep 3306
LISTEN 0 151 127.0.0.1:3306 0.0.0.0:*
この状態で、Docker のコンテナ(別のマシンと同じ扱いになる)からホストの MySQL に接続すると、Connection refused になりました。
== コンテナ → 172.17.0.1:3306(ホストの MySQL)
java.net.ConnectException: Connection refused (23 ms)
直し方:MySQL の設定ファイル(Ubuntu は /etc/mysql/mysql.conf.d/mysqld.cnf)を変え、MySQL を再起動します。
[mysqld]
bind-address = 0.0.0.0 # すべてのネットワークで待ち受ける(特定のIPだけにもできる)
$ ss -ltn | grep 3306
LISTEN 0 151 0.0.0.0:3306 0.0.0.0:*
== コンテナ → 172.17.0.1:3306
OK: /172.17.0.1:3306
待ち受けを広げたら、ファイアウォールで接続元を絞ることと、MySQL のユーザーを 'app'@'192.168.10.%' のように接続元のホストを指定して作ることを合わせて行います。ユーザーのホストが合わないと、今度は Host '...' is not allowed to connect to this MySQL server(ERROR 1130)になります。
例3:Docker で localhost に接続している
アプリを Docker のコンテナで動かすと、コンテナの中の localhost はコンテナ自身を指します。コンテナから localhost:3306 に接続すると、ホストの MySQL が動いていても Connection refused になりました。
== コンテナ → localhost:3306
java.net.ConnectException: Connection refused (28 ms)
| MySQL の場所 | 接続URLのホスト |
|---|---|
| 同じ docker compose の別サービス | サービス名(jdbc:mysql://db:3306/app) |
| ホストのマシン(Docker Desktop) | host.docker.internal |
| ホストのマシン(Linux の Docker) | host.docker.internal(compose で extra_hosts: ["host.docker.internal:host-gateway"] を付ける)、または docker0 の IP |
| 別のサーバー・クラウドの DB | そのホスト名・IP |
docker compose では、アプリが MySQL の準備完了より先に起動して、このエラーになることもあります。depends_on だけでは、コンテナが起動するまでしか待ちません。ヘルスチェックを付けて、準備ができるまで待たせます。
services:
db:
image: mysql:8.4
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: app
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-pexample"]
interval: 5s
retries: 20
app:
build: .
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://db:3306/app
depends_on:
db:
condition: service_healthy
例4:つながっていた接続が wait_timeout で切られた
MySQL は、何も通信しない接続を wait_timeout(既定 28800 秒=8時間) で切ります。夜間に使われなかった接続を、朝いちばんに使うと出る、というのが典型です。
wait_timeout を5秒にして、7秒待ってから SQL を送りました。
mysql> SET SESSION wait_timeout = 5;
mysql> SELECT 'before' AS t;
+--------+
| before |
+--------+
(7秒待つ)
mysql> SELECT 'after' AS t;
ERROR 4031 (HY000): The client was disconnected by the server because of inactivity. See wait_timeout and interactive_timeout for configuring this behavior.
MySQL 8.0.24 以降のサーバーは、切る前にこのエラー(4031)を送ります。Connector/J 9.7.0 のソースでは、このエラーを受け取ると CommunicationsException として投げる作りになっているため、Java ではメッセージに The client was disconnected by the server because of inactivity が入ります。それより前のサーバーでは、The last packet successfully received from the server was 28,800,xxx milliseconds ago の形になります。
直し方:wait_timeout を延ばすのではなく、接続プール側で、サーバーに切られる前に接続を入れ替えるようにします。Spring Boot の既定の接続プールは HikariCP です。
# application.yml(Spring Boot + HikariCP)
spring:
datasource:
url: jdbc:mysql://db:3306/app
hikari:
max-lifetime: 1740000 # 29分。DB やネットワーク機器の切断時間より数秒以上短く
keepalive-time: 120000 # 2分ごとに使っていない接続を確認する
connection-timeout: 30000 # プールから接続を借りるまで待つ時間
| HikariCP の設定 | 既定値 | 決め方 |
|---|---|---|
maxLifetime |
30分 | wait_timeout、ロードバランサー・ファイアウォールの無通信タイムアウトのうち一番短いものより、数秒以上短く |
keepaliveTime |
2分 | 無通信で切るネットワーク機器があるなら、その時間より短く |
connectionTimeout |
30秒 | プールが空のときに待つ時間 |
クラウドの DB では、ロードバランサーや NAT ゲートウェイの無通信タイムアウトが wait_timeout より短いことがあります。この場合、MySQL の設定を延ばしても直りません。maxLifetime をその時間より短くします。
接続URLの autoReconnect=true は、Connector/J の説明でも「推奨しない」とされています。トランザクションの途中で再接続すると、セッションの状態やデータの整合性に影響するためです。
例5:TLS のバージョンが合わない
Caused by: javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
TLS 1.0・1.1 しか使えない以前の版の MySQL に、新しい Java から接続すると出ます。最近の Java は TLS 1.0・1.1 を既定で無効にしているためです。TLS 1.1 だけを許可した Java のクライアントで接続すると、同じメッセージになりました。
| 直し方 | 内容 |
|---|---|
| MySQL を TLS 1.2 以上に対応させる(推奨) | MySQL のバージョンを上げる、または TLS 1.2 を有効にする |
| 接続URLで TLS のバージョンを指定 | tlsVersions=TLSv1.2,TLSv1.3 |
| TLS を使わない | sslMode=DISABLED。社内ネットワークでも盗み見の危険があるため、検証環境以外では使わない |
似ているが別のエラー
| エラー文 | 原因 | 直し方 |
|---|---|---|
Access denied for user 'app'@'172.17.0.2' (using password: YES) |
ユーザー名・パスワード・接続元ホストの間違い(通信はできている) | ユーザーとホストの組み合わせを確認 |
Host '...' is not allowed to connect to this MySQL server |
接続元のホストが許可されていない | ユーザーを接続元のホストで作る |
Public Key Retrieval is not allowed |
caching_sha2_password の認証で、TLS を使わずに接続した |
TLS で接続する。検証環境なら allowPublicKeyRetrieval=true |
Too many connections |
max_connections(既定 151)を超えた |
接続プールの最大数の合計を見直す。接続を閉じ忘れていないか確認 |
Packet for query is too large |
max_allowed_packet を超える SQL・データ |
一度に送るデータを分ける、または値を上げる |
確認の手順(チェックリスト)
| 順番 | 確認すること | コマンド・方法 |
|---|---|---|
| 1 | 2行目は「not received any packets」か「successfully received」か | つながらないのか、途中で切れたのか |
| 2 | 一番下の Caused by: |
上の表で原因を絞る |
| 3 | アプリのマシンから DB のポートに届くか | java Probe.java ホスト 3306、nc -vz ホスト 3306 |
| 4 | MySQL の待ち受け | ss -ltn | grep 3306、SHOW VARIABLES LIKE 'bind_address' |
| 5 | Docker なら接続先のホスト名 | localhost になっていないか、サービス名か |
| 6 | 途中で切れるなら、切断までの時間 | wait_timeout、ネットワーク機器のタイムアウト、HikariCP の maxLifetime |
よくある質問
Q. 朝いちばんの処理だけエラーになり、2回目からは動きます。
A. 夜間に使われなかった接続が、wait_timeout やネットワーク機器のタイムアウトで切られています(例4)。HikariCP の maxLifetime を、切られる時間より短くします。
Q. MySQL Workbench やコマンドからはつながるのに、アプリからだけつながりません。
A. 接続している場所が違うことが多い原因です。Workbench は自分のPCから、アプリはサーバーやコンテナから接続しています。アプリが動いているマシン(コンテナ)の中で Probe.java や nc を実行して確かめます。
Q. autoReconnect=true を付ければ直りますか。
A. Connector/J の説明では、この設定は推奨されていません。切れた接続を使った SQL はエラーになり、次のトランザクションから再接続する動きで、セッションの状態が失われます。接続プールの設定で対応します。
Q. MariaDB の JDBC ドライバでも同じですか。
A. エラーの文言は違いますが、原因と直し方の考え方(つながらないのか、途中で切れたのか、Caused by を見る)は同じです。
まとめ
Communications link failureは通信の失敗。SQL・パスワードの問題ではない- 2行目が「not received any packets」なら、一度もつながっていない。ポート・
bind-address・Docker のlocalhost・ファイアウォールを調べる - 「successfully received ... milliseconds ago」や inactivity なら、途中で切れた。
wait_timeoutとネットワーク機器のタイムアウトを調べる - 一番下の
Caused by:が本当の原因。Connection refusedはポート、Connect timed outは経路 - 途中で切れる問題は、HikariCP の
maxLifetimeを切断時間より短くして直す。autoReconnectには頼らない
参考・出典
確認日はいずれも 2026年10月10日です。
- MySQL 8.0 Reference Manual「MySQL server has gone away」:https://dev.mysql.com/doc/refman/8.0/en/gone-away.html
- MySQL Connector/J 9.7.0 ソース(メッセージの定義・接続プロパティの説明):https://github.com/mysql/mysql-connector-j
- HikariCP(README の設定項目):https://github.com/brettwooldridge/HikariCP
- Docker Docs「Control startup and shutdown order in Compose」:https://docs.docker.com/compose/how-tos/startup-order/
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Communications link failureの原因と直し方|MySQL」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。