- JAVA
SocketTimeoutExceptionの直し方|Read/connectの違い
java.net.SocketTimeoutException は、自分で設定した待ち時間(タイムアウト)を超えたときの例外です。 メッセージで「どこで待っていたか」が分かります。
| メッセージ | どこで待っていたか | 多い原因 |
|---|---|---|
SocketTimeoutException: Read timed out |
接続できたあと、応答(データ)を待っていた | 相手の処理が遅い・止まっている |
SocketTimeoutException: connect timed out(Java 17 以降は Connect timed out) |
接続(TCP のつなぎ込み)を待っていた | 宛先に届かない(ファイアウォール・経路・IP 違い) |
ConnectException: Connection timed out |
接続を待っていたが、タイムアウトを設定していなかった | 同上。OS の上限(Linux で約2分)で打ち切られた |
HttpTimeoutException: request timed out |
java.net.http.HttpClient で応答を待っていた |
相手の処理が遅い |
HttpConnectTimeoutException: HTTP connect timed out |
HttpClient で接続を待っていた |
宛先に届かない |
直し方は、「接続」と「読み取り」のどちらで止まったかで分かれます。 接続で止まるなら経路・宛先の問題で、待ち時間を延ばしても直りません。読み取りで止まるなら、相手の処理時間に合わせて待ち時間を決めるか、相手を速くします。
確認環境:OpenJDK 1.8.0_504・11.0.32.1・17.0.20.1・21.0.10・25.0.4.1(Linux)。応答しないサーバーは、接続を受け付けて何も返さない Python のサーバーで、届かない宛先は、iptables で送信を捨てる宛先(192.0.2.1、文書用の予約アドレス)で再現しました。JDBC は PostgreSQL JDBC ドライバ 42.7.8 を、PostgreSQL の通信手順の一部だけを返す試験用サーバーにつないで確かめました。MySQL Connector/J と Spring の設定はドキュメントで確認しています(確認日 2026年10月13日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「SocketTimeoutExceptionの直し方|Read/connectの違い」
Read timed out と connect timed out の違い
HTTP の通信は、「① 接続する(TCP の3ウェイハンドシェイク)→ ② 要求を送る → ③ 応答を読む」の順に進みます。
| 段階 | 待つもの | Java の設定 | 超えたとき |
|---|---|---|---|
| ① 接続 | 相手が接続を受け付ける返事 | connectTimeout |
connect timed out |
| ③ 読み取り | 相手から届く次のデータ | readTimeout(soTimeout) |
Read timed out |
接続できなかったのか、接続できたが返事が来なかったのかで、疑う場所がまったく違います。
connect timed out:パケットが相手まで届いていない(または返事が戻らない)。セキュリティグループ・ファイアウォール・ルーティング・IP アドレスやポートの誤り・相手のマシンが止まっている、などを疑うRead timed out:相手には届いている。相手のアプリが遅い・止まっている・DB 待ち、などを疑う
相手のポートが閉じている(プロセスが動いていない)ときは、どちらでもなく、すぐに ConnectException: Connection refused になります。Connection refused との見分け方は、関連記事「Connection refused・Read timed outの違いと直し方」で扱っています。
Java の API ごとのメッセージ一覧(実行結果)
接続のタイムアウトと読み取りのタイムアウトをそれぞれ 2 秒にして動かした結果です。かかった時間はどれも約 2.0〜2.2 秒でした。
Socket・HttpURLConnection
| 状況 | Java 8・11 | Java 17・21・25 |
|---|---|---|
Socket の読み取りで待ち切れない |
SocketTimeoutException: Read timed out |
SocketTimeoutException: Read timed out |
Socket の接続で待ち切れない |
SocketTimeoutException: connect timed out |
SocketTimeoutException: Connect timed out |
HttpURLConnection の GET・POST で応答なし |
SocketTimeoutException: Read timed out |
SocketTimeoutException: Read timed out |
HttpURLConnection で宛先に届かない |
SocketTimeoutException: connect timed out |
SocketTimeoutException: Connect timed out |
| ポートが閉じている | ConnectException: Connection refused (Connection refused) |
ConnectException: Connection refused |
Java 17 では、connect の c が大文字になりました。 Java 17 で -Djdk.net.usePlainSocketImpl=true(Java 13 の JEP 353 で入れ替わる前の実装を使う設定)を付けると、小文字の connect timed out に戻りました。ログ監視でメッセージの文字列を条件にしているなら、大文字・小文字を区別しない条件にします。
java.net.http.HttpClient(Java 11 以降)
| 状況 | 例外とメッセージ(11・17・21・25。3行目は 11・21・25) |
|---|---|
HttpRequest の timeout 内に応答が来ない |
java.net.http.HttpTimeoutException: request timed out |
HttpClient の connectTimeout 内に接続できない |
java.net.http.HttpConnectTimeoutException: HTTP connect timed out |
connectTimeout なし・timeout だけ設定で、宛先に届かない |
HttpConnectTimeoutException: HTTP connect timed out(約 2.3〜2.5 秒) |
HttpClient は SocketTimeoutException を投げません。 例外の親子関係を Java 21 で確かめると、次のとおりでした。
SocketTimeoutException → InterruptedIOException → IOException
HttpConnectTimeoutException → HttpTimeoutException → IOException
HttpTimeoutException → IOException
ConnectException → SocketException → IOException
HttpURLConnection から HttpClient に移すと、catch (SocketTimeoutException e) では受け止められなくなります。両方を受けるなら、HttpTimeoutException も並べて書きます。
try {
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
} catch (HttpConnectTimeoutException e) { // 先に子クラスを書く
// 接続できなかった:宛先・経路の問題
} catch (HttpTimeoutException e) {
// 接続後、応答が来なかった
} catch (SocketTimeoutException e) {
// HttpURLConnection・Socket の場合
}
HttpClient の基本的な使い方は、関連記事「Java HttpClientの使い方|GET・POSTでJSON送信」で扱っています。
タイムアウトを設定しないと(Connection timed out)
Socket.connect をタイムアウトなしで呼び、届かない宛先につないだ結果です。
| 版 | 例外とメッセージ | かかった時間 |
|---|---|---|
| Java 8・11 | java.net.ConnectException: Connection timed out (Connection timed out) |
134.3〜134.4 秒 |
| Java 17・21・25 | java.net.ConnectException: Connection timed out |
134.3〜134.4 秒 |
Connection timed out は Java のタイムアウトではなく、OS が接続をあきらめたときのメッセージです。 例外も SocketTimeoutException ではなく ConnectException になります。確かめた Linux は net.ipv4.tcp_syn_retries = 6(接続の要求を6回送り直す設定)で、約 134 秒かかりました。待ち時間は OS の設定で変わります。
URLConnection の API ドキュメントでは、setConnectTimeout・setReadTimeout の 0 は「無限」を表します。何も設定しないと 0 です。読み取りのタイムアウトを設定しないと、相手が返事をしない限り、スレッドはずっと止まったままになります。
タイムアウト設定の一覧
| 使うもの | 接続のタイムアウト | 読み取りのタイムアウト | 既定値(ドキュメント) |
|---|---|---|---|
Socket |
connect(addr, ミリ秒) |
setSoTimeout(ミリ秒) |
0(無限) |
HttpURLConnection |
setConnectTimeout(ミリ秒) |
setReadTimeout(ミリ秒) |
0(無限) |
java.net.http.HttpClient |
HttpClient.Builder.connectTimeout(Duration) |
HttpRequest.Builder.timeout(Duration) |
設定しないと無限 |
| PostgreSQL JDBC | connectTimeout(秒) |
socketTimeout(秒) |
10 秒 / 0(無効) |
| MySQL Connector/J | connectTimeout(ミリ秒) |
socketTimeout(ミリ秒) |
0 / 0 |
| Spring Boot 4.1 | spring.http.clients.connect-timeout |
spring.http.clients.read-timeout |
— |
Spring SimpleClientHttpRequestFactory |
setConnectTimeout(Duration) |
setReadTimeout(Duration) |
システムの既定 |
Spring JdkClientHttpRequestFactory |
渡す HttpClient の connectTimeout |
setReadTimeout(Duration) |
システムの既定 |
PostgreSQL は秒、MySQL はミリ秒です。 同じ名前の connectTimeout=10 でも、PostgreSQL では 10 秒、MySQL では 10 ミリ秒になります。
コピペ用:各 API の設定例
// Socket
Socket s = new Socket();
s.connect(new InetSocketAddress("api.example.com", 443), 3_000); // 接続 3 秒
s.setSoTimeout(10_000); // 読み取り 10 秒
// HttpURLConnection
HttpURLConnection c = (HttpURLConnection) new URL("https://api.example.com/").openConnection();
c.setConnectTimeout(3_000);
c.setReadTimeout(10_000);
// java.net.http.HttpClient
HttpClient client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(3))
.build();
HttpRequest req = HttpRequest.newBuilder(URI.create("https://api.example.com/"))
.timeout(Duration.ofSeconds(10))
.build();
# JDBC URL
jdbc:postgresql://db.example.com:5432/app?connectTimeout=3&socketTimeout=30
jdbc:mysql://db.example.com:3306/app?connectTimeout=3000&socketTimeout=30000
# Spring Boot 4.1(RestClient・RestTemplate など、自動設定される HTTP クライアント全体)
spring.http.clients.connect-timeout=3s
spring.http.clients.read-timeout=10s
// Spring:RestClient に個別に設定する
SimpleClientHttpRequestFactory f = new SimpleClientHttpRequestFactory();
f.setConnectTimeout(Duration.ofSeconds(3));
f.setReadTimeout(Duration.ofSeconds(10));
RestClient restClient = RestClient.builder().requestFactory(f).build();
Spring の HTTP クライアントの選び方は、関連記事「RestClient・WebClient・RestTemplateの違い|移行対応表」で扱っています。値の決め方(呼び出しが何段にも重なるときの計算)は、関連記事「タイムアウト設計の値の決め方|接続・読み取りの違いと多段の計算例」で扱っています。
読み取りのタイムアウトは「全体の時間」ではない
readTimeout は「次のデータが来るまで」
URLConnection.setReadTimeout のドキュメントでは、「読み取れるデータが来る前に時間が切れると」例外になる、と書かれています。1回の読み取りごとの待ち時間で、応答全体の時間ではありません。
1 秒に 1 バイトずつ、10 バイトの本文を返すサーバーに、setReadTimeout(2000) でつないだ結果です(Java 11・21・25 で同じ)。
read 10 bytes
no exception
elapsed 10.1 s
読み取りのタイムアウトは 2 秒でも、全体で 10.1 秒かかり、例外になりませんでした。 少しずつでもデータが届く限り、待ち続けます。全体の上限が必要なら、別のしくみで打ち切ります(HttpClient の sendAsync と CompletableFuture.orTimeout など)。
HttpClient の timeout は本文の受信を含まない(Java 25 まで)
応答のヘッダーだけを返し、本文の途中で止まるサーバーに、HttpRequest の timeout を 2 秒にしてつなぎました。
| 版 | 結果 |
|---|---|
| Java 11・21・25 | 20 秒たっても例外にならず、外から止めた |
比較:HttpURLConnection(setReadTimeout(2000)) |
status 200 のあと、本文の読み取りで Read timed out(2.1 秒) |
HttpRequest.Builder.timeout のドキュメントでは「応答がその時間内に受け取れないと HttpTimeoutException」とあり、確かめた版では、ヘッダーを受け取った時点で時間の計測が終わっていました。OpenJDK では、この範囲を本文の受信まで広げる変更(JDK-8208693「HttpClient: Extend the request timeout's scope to cover the response body」)が、2025年12月に開発中の版に取り込まれています。Java 25 までは、本文を受け取る時間には別の上限を付けます。
// 全体に上限を付ける例(Java 11 以降)
HttpResponse<String> res = client.sendAsync(req, HttpResponse.BodyHandlers.ofString())
.orTimeout(15, TimeUnit.SECONDS) // 本文の受信まで含めて 15 秒
.join(); // 超えると CompletionException(原因は TimeoutException)
Java 21 で、本文の途中で止まるサーバーにこのコード(上限 5 秒)でつなぐと、5.0 秒で CompletionException(原因は java.util.concurrent.TimeoutException)になり、打ち切れました。
JDBC(PostgreSQL・MySQL)の場合
PostgreSQL JDBC ドライバ 42.7.8 の実行結果
JDBC のドライバは、SocketTimeoutException を SQLException で包んで投げます。getCause() をたどると、元の SocketTimeoutException が見えます。 Java 21 での結果です。
| 状況(URL の設定) | 例外のメッセージ | SQLState | 原因(cause) | 時間 |
|---|---|---|---|---|
届かない宛先(connectTimeout=2) |
The connection attempt failed. |
08001 | SocketTimeoutException: Connect timed out |
2.6 秒 |
| 届かない宛先(設定なし) | The connection attempt failed. |
08001 | SocketTimeoutException: Connect timed out |
10.1 秒 |
接続後に何も返さない(loginTimeout=2) |
Connection attempt timed out. |
08001 | なし | 2.1 秒 |
接続後に何も返さない(socketTimeout=2) |
The connection attempt failed. |
08001 | SocketTimeoutException: Read timed out |
2.3 秒 |
SQL の結果が返らない(socketTimeout=2) |
An I/O error occurred while sending to the backend. |
08006 | SocketTimeoutException: Read timed out |
2.5 秒 |
| ポートが閉じている | Connection to 127.0.0.1:15499 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections. |
08001 | ConnectException: Connection refused |
0.3 秒 |
- 設定なしでも 10.1 秒で止まったのは、PostgreSQL JDBC の
connectTimeoutの既定値が 10 秒だからです(ドキュメントの値と一致) socketTimeoutの既定値は 0(無効)です。SQL が終わらないと、設定しない限りずっと待ちます- Java 8 で同じことをすると、原因の文面だけが
connect timed out(小文字)でした
ドキュメントでは、socketTimeout を超えると「接続は閉じられる」とあります。socketTimeout は SQL を止める設定ではなく、通信を切る設定です。 サーバー側では SQL が動き続けていることがあります。SQL 自体に上限を付けるなら、Statement.setQueryTimeout か PostgreSQL の statement_timeout を使います。statement_timeout で止まったときのエラーは、関連記事「statement timeoutの直し方|PostgreSQL」で扱っています。
MySQL Connector/J(ドキュメントより)
| プロパティ | 説明(ドキュメント) | 既定値 | 単位 |
|---|---|---|---|
connectTimeout |
ソケットの接続のタイムアウト。0 はタイムアウトなし | 0 | ミリ秒 |
socketTimeout |
ネットワークのソケット操作のタイムアウト。0 はタイムアウトなし | 0 | ミリ秒 |
MySQL Connector/J のトラブルシューティングのドキュメントには、Communications link failure – Last packet sent to the server was X ms ago というメッセージが載っています。ドキュメントでは、問い合わせ中の通信の問題では SQLState が 08S01 になるとされ、リトライの例もこの値で判定しています。この場合も getCause() で、接続と読み取りのどちらで止まったかを確かめます。JDBC の接続の書き方は、関連記事「Java JDBCでMySQL接続|PreparedStatementとCRUD」で扱っています。
原因の切り分け手順
| 手順 | コマンド・見るもの | 分かること |
|---|---|---|
| 1. メッセージを見る | connect か Read か |
接続と読み取りのどちらか |
| 2. 同じマシンから接続だけ試す | nc -vz -w 3 ホスト ポート |
宛先まで届くか |
| 3. 応答時間を測る | curl -o /dev/null -s -w '%{time_connect} %{time_starttransfer}\n' URL |
接続と最初の1バイトまでの時間 |
| 4. 名前解決を確かめる | getent hosts ホスト名 |
思っている IP につないでいるか |
| 5. 相手のログ・負荷を見る | アクセスログ・遅いクエリのログ | 相手側で遅いのか |
connect timed out で nc もつながらないなら、Java のコードではなく経路の問題です。 クラウドなら、セキュリティグループ・ネットワーク ACL・NAT の設定を見ます。コマンドの使い方は、関連記事「Linuxネットワークコマンド一覧|ip/ss/ncで障害切り分け」と、関連記事「curlコマンドの使い方|よく使うオプションとAPIの確認方法」で扱っています。
リトライするときの注意
Read timed out では、相手が処理していることがある
試験用サーバーのログでは、HttpURLConnection の POST が Read timed out になったとき、サーバーには要求が1件届いていました(5つの版で各1件)。
POST /huc-post HTTP/1.1 ← サーバーが受け取った要求(各版1件)
Read timed out は「返事を待ち切れなかった」だけで、相手が処理しなかったとは限りません。注文・送金・メール送信のような、2回実行すると困る処理を、そのまま送り直すと二重に実行されることがあります。
| 例外 | 相手に届いたか | リトライの目安 |
|---|---|---|
connect timed out・Connection refused |
届いていない | 送り直しても二重にはならない |
Read timed out・HttpTimeoutException |
届いている可能性がある | 冪等(何度やっても結果が同じ)な処理か、冪等キーがあるときだけ |
二重実行を防ぐ設計は、関連記事「冪等性とは|APIの冪等キー実装と二重登録を防ぐリトライ設計の一覧」で扱っています。
間隔を空け、回数に上限を付ける
相手が混んでいて遅いときに、すぐ何度も送り直すと、さらに混みます。リトライは、間隔を少しずつ延ばす(指数バックオフ)・ばらつきを足す(ジッター)・回数の上限を決めるの3つをそろえます。
static <T> T withRetry(Callable<T> call, int maxAttempts) throws Exception {
long waitMs = 200;
for (int attempt = 1; ; attempt++) {
try {
return call.call();
} catch (HttpConnectTimeoutException | ConnectException e) {
// 届いていないので送り直せる
if (attempt >= maxAttempts) throw e;
}
Thread.sleep(waitMs + ThreadLocalRandom.current().nextLong(waitMs)); // ジッター
waitMs = Math.min(waitMs * 2, 5_000);
}
}
この例は、接続できなかった場合だけ送り直します。読み取りで待ち切れなかった場合も送り直すなら、その処理が冪等であることを確かめてから、catch に HttpTimeoutException を足します。間隔の決め方は、関連記事「指数バックオフとは?リトライ間隔の決め方とジッターの実装」で扱っています。
よくある質問
Q. タイムアウトを長くすれば直りますか。
A. connect timed out は、多くの場合、長くしても直りません。届かない宛先は、何秒待っても届かないためです。Read timed out は、相手の処理時間が設定より長いだけなら、延ばすと例外は消えます。ただし、呼び出し元(ロードバランサー・API Gateway・Lambda など)の上限より長くすると、手前で切られます。Lambda で起きる場合は、関連記事「Task timed out afterの直し方|Lambdaタイムアウト原因別」で扱っています。
Q. Read timed out が、決まった秒数ちょうどで出ます。
A. 設定した読み取りのタイムアウトどおりです。秒数が設定と合わないときは、ライブラリや Spring Boot の設定が上書きしていないか、getReadTimeout() で実際の値を確かめます。
まとめ
Read timed outは接続後の応答待ち、connect timed outは接続待ちで時間切れ- Java 17 以降は
Connect timed out(大文字)。ログ監視の条件に注意 - タイムアウトなしで届かないと、OS 由来の
ConnectException: Connection timed out(確かめた Linux で約 134 秒) HttpClientはHttpTimeoutException・HttpConnectTimeoutExceptionを投げ、SocketTimeoutExceptionの子ではないreadTimeoutは1回の読み取りの待ち時間。HttpClientのtimeoutは Java 25 まで本文の受信を含まない- JDBC は
SQLExceptionのgetCause()を見る。PostgreSQL は秒、MySQL はミリ秒 Read timed outのあとのリトライは、相手が処理済みかもしれない前提で
参考・出典
確認日はいずれも 2026年10月13日です。
- Java SE 21 API「URLConnection」:https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/net/URLConnection.html
- Java SE 21 API「HttpClient.Builder」:https://docs.oracle.com/en/java/javase/21/docs/api/java.net.http/java/net/http/HttpClient.Builder.html
- Java SE 25 API「HttpRequest.Builder」:https://docs.oracle.com/en/java/javase/25/docs/api/java.net.http/java/net/http/HttpRequest.Builder.html
- OpenJDK「JEP 353: Reimplement the Legacy Socket API」:https://openjdk.org/jeps/353
- OpenJDK「JDK-8208693」:https://bugs.openjdk.org/browse/JDK-8208693
- PostgreSQL JDBC Driver「Initializing the Driver」(接続パラメータ):https://jdbc.postgresql.org/documentation/use/
- MySQL Connector/J「Networking」:https://dev.mysql.com/doc/connector-j/en/connector-j-connp-props-networking.html
- Spring Boot「HTTP Clients」:https://docs.spring.io/spring-boot/reference/io/rest-client.html
- Spring Framework API「SimpleClientHttpRequestFactory」:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/client/SimpleClientHttpRequestFactory.html
- MySQL Connector/J「Troubleshooting Connector/J Applications」:https://dev.mysql.com/doc/connectors/en/connector-j-usagenotes-troubleshooting.html
- Spring Framework API「JdkClientHttpRequestFactory」:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/client/JdkClientHttpRequestFactory.html
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「SocketTimeoutExceptionの直し方|Read/connectの違い」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。