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期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?