ETIMEDOUT(Connection timed out)
接続が応答なしで固まる原因を、拒否を返すECONNREFUSEDとの決定的な違いから切り分け、ping/traceroute/curl -v でドロップを特定し、適切なタイムアウト設計まで持ち帰れる。
- ETIMEDOUT は SYN を送っても ACK が返らず、OS の再送を使い切って諦めた状態。RST で即座に拒否される ECONNREFUSED とは根本的に別物で、原因の方向がまったく異なる。
- 主因は経路不通・ファイアウォールでのサイレントドロップ・相手サーバーの過負荷(backlog溢れ)・DNS 解決の遅延。パケットが「拒否された」のか「消えた」のかで犯人が変わる。
- 診断は curl -v で TLS 前か接続時かを確定し、ping と traceroute で経路を、tcpdump で SYN 再送を観測して切り分ける。対処は到達性の修復とアプリ側タイムアウト・リトライの設計。
一言でいうと(このエラーが何を意味するか)
ETIMEDOUT(多くのライブラリで Error: connect ETIMEDOUT や Connection timed out)は、接続の相手が制限時間内に一切応答しなかったことを示すエラーです。TCP では接続開始時にクライアントが SYN パケットを送り、相手の SYN-ACK を待ちます。この応答が返らないと OS はカーネルのタイマーに従って SYN を数回再送し、それでも無応答なら接続試行を打ち切って ETIMEDOUT を返します。
決定的なのは ECONNREFUSED との違いです。両者は「つながらない」点では同じでも、相手の反応がまるで逆です。
| 観点 | ETIMEDOUT | ECONNREFUSED |
|---|---|---|
| 相手の応答 | 何も返ってこない(沈黙) | RST(リセット)が即座に返る |
| 典型的な原因 | 経路不通・FWドロップ・過負荷・DNS遅延 | 宛先ポートで誰も待ち受けていない |
| 発生までの時間 | 数秒〜数十秒(再送を使い切る) | ほぼ即時(1RTT) |
| 犯人の方向 | 経路・中間装置・相手の飽和を疑う | 相手ホストは生きているがサービス未起動を疑う |
つまり ECONNREFUSED は「ホストは生きていて、はっきり断られた」、ETIMEDOUT は「返事すら来ない」。前者はポート番号やサービス起動状態を、後者は経路・中間装置・相手の飽和を疑うのが出発点です。
体感時間は強力な手がかりです。1秒未満で失敗するなら RST が返る ECONNREFUSED か DNS の即時失敗。5〜60秒かけて失敗するなら SYN 再送を使い切った本物の ETIMEDOUT で、パケットが経路のどこかで消えています。Linux の既定では SYN を約6回再送し、合計およそ127秒(tcp_syn_retries=6)で諦めます。
横にスクロール
よくある原因(複数を具体的に、頻度順)
-
ファイアウォール/セキュリティグループでのサイレントドロップ(最頻)。拒否には「REJECT(RSTやICMPを返す)」と「DROP(黙って捨てる)」があり、クラウドのセキュリティグループや多くの企業FWは既定で DROP します。DROP されるとクライアントには何も返らないため、必然的に
ETIMEDOUTになります。ポートの開放漏れ、送信元IP制限、片方向だけ開いている(戻りが塞がれている)ケースが典型です。 -
経路不通(ルーティング/到達性の問題)。宛先ホストがダウンしている、ルートテーブルの設定漏れ、NAT/VPN 経由の非対称経路、オンプレとクラウド間の経路広告漏れなどで、
SYNが相手に届かない、または戻りが返らない状態です。 -
相手サーバーの過負荷(accept backlog 溢れ)。相手プロセスは生きていても、
accept()キュー(net.core.somaxconnとlisten()の backlog)が満杯だと、確立途中の接続が溢れて破棄され、クライアントからは応答なしに見えます。負荷スパイク時やスレッドプール枯渇時に散発的なETIMEDOUTとして現れます。 -
DNS 解決の遅延・タイムアウト。名前解決が遅い、または DNS サーバーが無応答だと、TCP 接続に到達する前にアプリの総タイムアウトを超えます。厳密には接続タイムアウトと別物ですが、症状(固まってから失敗)が似ているため混同されがちです。Node.js では
getaddrinfo ETIMEDOUTとして区別できます。
毎回ではなく「ときどき」タイムアウトする場合、経路そのものは通っています。疑うべきは相手の accept backlog 溢れ、コネクションプール枯渇、NAT テーブルやロードバランサのポート枯渇(SNAT ポート不足)です。成功と失敗が混在する=飽和のサインと考えてください。
診断の手順(切り分け方・見るべきログ/コマンド)
手順1: どの段階で失敗しているかを curl -v で確定する。 ログの1行がすべてを教えます。
curl -v --connect-timeout 5 https://api.example.com/
# "Trying 203.0.113.10:443..." で止まる → TCP接続そのものが不成立(本記事の対象)
# "Connected to ..." の後で止まる → 接続は成立、TLS/アプリ層の問題
# 名前解決で止まる → DNS の問題
手順2: 相手ポートへの到達性を直接叩く。 ping は ICMP なので通っても TCP ポートが塞がれていることは多々あります。目的のポートへ届くかを見ます。
# TCPレベルでポートの開放を確認(ncが無ければ /dev/tcp)
nc -vz -w 5 api.example.com 443
# 即 refused → ECONNREFUSED(サービス未起動)
# 5秒無応答で失敗 → ドロップ(FW/経路)
timeout 5 bash -c '</dev/tcp/api.example.com/443' && echo OPEN || echo "DROP/CLOSED"
手順3: 経路のどこで消えるかを追う。 traceroute(Windows は tracert)で応答が途切れるホップを見ます。特定ホップ以降がすべて * * * なら、その先で経路断かフィルタが起きています。
traceroute -n -w 2 api.example.com # UDP。途中から * ばかりなら経路/FW を疑う
traceroute -T -p 443 -n api.example.com # 実ポートへTCPで。ICMP遮断環境で有効
手順4: パケットドロップを直接観測する。 これが最終確定です。SYN が出ているのに SYN-ACK が返らず、SYN の再送だけが並ぶなら、パケットが往路か復路で捨てられている動かぬ証拠です。
sudo tcpdump -n -i any "host api.example.com and tcp port 443"
# 送信側に SYN が複数(再送)、相手からの SYN-ACK が皆無 → ドロップ確定
# ss -tan で SYN-SENT のまま張り付く接続も傍証になる
SYN は相手に届いているのに戻りが塞がれている「非対称ルーティング」では、相手側の tcpdump には SYN が見え SYN-ACK も送出されているのに、クライアントには届きません。可能なら両端で同時に tcpdump を取り、どちら向きのパケットが欠けているかを突き止めるのが最短です。
解決と予防(対処と再発防止)
到達性を直す(根本対処)。 ドロップが原因なら、FW/セキュリティグループで対象ポートを開け、戻り方向(ステートフルなら通常は自動、そうでなければエフェメラルポート範囲)も確認します。経路不通ならルートテーブル、VPN/NAT の設定、DNS レコードを是正します。過負荷が原因なら net.core.somaxconn と listen() backlog を引き上げ、アプリの並行数やコネクションプール上限、上流のスケールを見直します。
タイムアウトを明示的に設計する(再発防止の要)。 多くのクライアントは既定のOSタイムアウトに任せており、失敗確定まで数十秒スレッドを占有します。これがスレッドプールを食い潰し、障害を連鎖させます。接続タイムアウトと読み取りタイムアウトは必ず分けて短く設定してください。
// 接続は速く諦め、読み取りは用途に応じて別枠にする
const res = await fetch(url, {
signal: AbortSignal.timeout(3000), // 全体の上限。接続で固まっても即諦める
});
// libcurl系: --connect-timeout(接続)と --max-time(全体)を別々に指定する
再試行はバックオフとサーキットブレーカーで守る。 ETIMEDOUT は一過性のことも多いため指数バックオフ+ジッターでの再試行が有効ですが、相手が飽和しているときに素朴に再試行すると傷口を広げます。連続失敗でサーキットブレーカーを開き、一定時間フェイルファストへ切り替えるのが定石です。TCP レベルでの早期検知には TCP_USER_TIMEOUT や Keepalive も併用できます。
TCP のハンドシェイクと再送の内部動作はネットワーク、FW・セキュリティグループの拒否ポリシー設計はセキュリティ、タイムアウトとリトライを組み込んだ耐障害設計はDevOpsを参照してください。
ETIMEDOUT=応答なし(SYN再送を使い切る)、ECONNREFUSED=RSTで即拒否。原因の方向が真逆- DROP(黙って破棄)と REJECT(RST/ICMPを返す)の違いが、タイムアウトになるか即失敗になるかを決める
- 断続的な
ETIMEDOUTは経路ではなく容量問題(accept backlog・プール・SNATポート枯渇)を疑う - 診断は curl -v で段階を特定 → traceroute で経路 → tcpdump で
SYN再送を観測して確定 - 対処の核心は接続と読み取りのタイムアウトを分離し、バックオフとサーキットブレーカーで連鎖障害を防ぐこと
エラー辞典の記事ガイド
ETIMEDOUT(Connection timed out)を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
ネットワーク
比較で見る軸
難易度: advanced / カテゴリ: エラー辞典 / タグ数: 6
導入後に効く点
主因は経路不通・ファイアウォールでのサイレントドロップ・相手サーバーの過負荷(backlog溢れ)・DNS 解決の遅延。パケットが「拒否された」のか「消えた」のかで犯人が変わる。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- エラー辞典
- タグ数
- 6
判断チェックリスト
- 自社の用途が「ネットワーク / TCP」に近いか確認する。
- 強みである「ETIMEDOUT は SYN を送っても ACK が返らず、OS の再送を使い切って諦めた状態。RST で即座に拒否される ECONNREFUSED とは根本的に別物で、原因の方向がまったく異なる。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。