◀ 15.

MySQL ERROR 1129|ホスト遮断の原因・カウンタ・解除前の確認

▶

ERROR 1129はホストキャッシュによる接続元の遮断です。単なるパスワード間違いや同時接続数の上限とは別です。まず接続元とエラーカウンタを記録し、原因を直す作業と遮断を解除する操作を分けます。

認証失敗と遮断対象の接続エラーを区別し、記録してから解除を計画する図

認証失敗と遮断対象のエラーを分けて読む

観測する値読み方
SUM_CONNECT_ERRORS遮断閾値と比較する値。接続に成功するとリセットされるため、過去すべての失敗総数ではない
COUNT_AUTHENTICATION_ERRORS認証失敗の別カウンタ。パスワード誤りだけを何度か起こしたことと1129の原因を同一視しない
COUNT_HOST_BLOCKED_ERRORS遮断によって拒否された接続の回数。DNSエラーの指標ではない
名前解決の各カウンタIP→名前/名前→IP/再確認の段階を区別。エラーの時刻と接続元を照合する

消す前に読み取りで記録する

以下はMySQL 8.0向けの読み取り例です。許可された管理接続で実行し、IP等をそのまま公開しないでください。Performance Schemaやホストキャッシュが無効、ループバック/Unixソケット接続、または既にキャッシュが消去された場合、行がないことだけで正常とは判断できません。

SELECT VERSION() AS server_version,
       @@GLOBAL.max_connect_errors AS max_connect_errors,
       @@GLOBAL.host_cache_size AS host_cache_size,
       @@GLOBAL.skip_name_resolve AS skip_name_resolve;

SELECT IP, HOST_VALIDATED, SUM_CONNECT_ERRORS,
       COUNT_HOST_BLOCKED_ERRORS, COUNT_HANDSHAKE_ERRORS,
       COUNT_AUTHENTICATION_ERRORS,
       COUNT_NAMEINFO_TRANSIENT_ERRORS, COUNT_NAMEINFO_PERMANENT_ERRORS,
       COUNT_ADDRINFO_TRANSIENT_ERRORS, COUNT_ADDRINFO_PERMANENT_ERRORS,
       COUNT_FCRDNS_ERRORS
FROM performance_schema.host_cache
ORDER BY IP;

host_cacheを空にする操作やhost_cache_sizeの変更は観測情報も消します。先に必要な範囲を保管し、NAT/プロキシ配下では複数アプリが同じ接続元IPに見えることも考慮します。アカウント削除・再起動・本番上限の変更はこの読取診断に含めません。

一次資料: MySQL 8.0ホストキャッシュ、各カウンタとTRUNCATE権限、8.0のFLUSH、8.4の構文、RDSの管理作業。

この記事の要点
  • 原因: 同一ホストからの遮断対象のプロトコルハンドシェイクエラーが max_connect_errorsに達することでブロックされた。認証失敗の累計そのものとは別
  • 解除: 記録と権限を確認して管理者が計画する。host_cache全体を消す操作で、対象版と必要権限が異なる
  • 再発防止: 遮断対象エラーの発生元と接続処理を修正する。根拠なく上限を10000や最大値へ増やさない
  • 原因調査: 時刻・接続元・ハンドシェイク・DNS・認証の各カウンタを区別する。番号だけで原因を決めない
  • DNS: 名前解決エラーの証拠を確認。skip-name-resolveやアカウント変更を初手にしない

エラー内容

ERROR 1129 (HY000): Host '192.168.1.10' is blocked because of many
connection errors; unblock with 'mysqladmin flush-hosts'

MySQL 8.0のSUM_CONNECT_ERRORSは、検証済みホストの遮断対象となるプロトコルハンドシェイクエラーを数えます。COUNT_AUTHENTICATION_ERRORSの累計と同一ではありません。閾値に達した接続元からの新規接続が拒否されます。並行接続では閾値を超える値もあり得るため、単純な総失敗回数として解釈しません。

解除前に記録と権限を確認する

下のmysqladmin/FLUSH/TRUNCATEは状態を変更する旧例です。 先に必要な診断情報を記録し、許可された管理経路を使います。アプリ用アカウントへ管理権限を追加して実行しないでください。キャッシュ全体の解除で、特定IPだけの解除ではありません。

方法 A: mysqladmin から

# 別のホスト(許可済み)または localhost から
mysqladmin -u root -p flush-hosts

方法 B: SQL で

旧コード末尾の権限コメントは訂正対象です。 MySQL 8.0のFLUSH HOSTSにはRELOAD、host_cacheのTRUNCATEにはその表のDROP権限が必要です。SYSTEM_VARIABLES_ADMINだけで両方を実行できる説明は誤りです。FLUSH HOSTSは8.0.23で非推奨となり、8.4では使えません。対象版の公式構文と管理サービスの制約を確認します。

-- MySQL 5.7
FLUSH HOSTS;

-- MySQL 8.0.23 以降は FLUSH HOSTS が非推奨
TRUNCATE TABLE performance_schema.host_cache;

-- どちらも RELOAD(FLUSH HOSTS)または SYSTEM_VARIABLES_ADMIN 権限が必要

ホストキャッシュを確認する

MySQL 5.7+ は performance_schema.host_cache でブロック理由を SQL で確認できます:

SELECT IP, HOST, HOST_VALIDATED, COUNT_HANDSHAKE_ERRORS,
       COUNT_AUTHENTICATION_ERRORS, COUNT_LOCAL_ERRORS,
       SUM_CONNECT_ERRORS
FROM performance_schema.host_cache;

-- COUNT_HANDSHAKE_ERRORS:   プロトコル不一致(古いクライアント等)
-- COUNT_AUTHENTICATION_ERRORS: 認証失敗
-- COUNT_LOCAL_ERRORS:        サーバ内部エラー
-- SUM_CONNECT_ERRORS:        max_connect_errors と比較されるカウンタ

max_connect_errorsの値と増量リスクを確認する

既定100を小さすぎるとは断定しません。 下のSET GLOBALは旧変更例で、上限を増やしても接続不良の原因は直りません。SUM_CONNECT_ERRORS・発生頻度・正常接続の状況を照合し、測定と承認なしに変更しないでください:

-- 現在値確認
SHOW VARIABLES LIKE 'max_connect_errors';

-- 動的変更(再起動まで有効)
SET GLOBAL max_connect_errors = 10000;

次の設定も旧例です。実際の読込先と既存値、名前解決とアカウントへの影響、再起動要否を確認します。connect_timeout=10も、それだけで元より緩和された証拠にはなりません。ファイルをそのまま追記/上書きしないでください:

# /etc/mysql/mysql.conf.d/mysqld.cnf

[mysqld]
max_connect_errors = 10000

# DNS 逆引きを完全に無効化(後述)
skip-name-resolve

# ハンドシェイクのタイムアウト緩和
connect_timeout = 10

根本原因の調査

典型原因確認対処
アプリのリトライ暴走アプリログで再接続ループ指数バックオフ実装、接続プール使用
名前解決の問題COUNT_NAMEINFO_* / COUNT_ADDRINFO_* / COUNT_FCRDNS_ERRORSを時刻と照合。COUNT_HOST_BLOCKED_ERRORSは遮断された回数DNSと実際の接続元を確認し、即座に名前解決を無効化しない
FW / SG でタイムアウトTCP 接続自体が timeoutセキュリティグループ・iptables 確認
ロードバランサのヘルスチェック定期的に接続失敗チェック方式を確認。挨拶後に切断するTCPチェック自体が原因候補になるため、TCPのみなら安全としない
クライアントが古すぎるCOUNT_HANDSHAKE_ERRORSと実クライアント版・通信断を照合古さを断定せず、プロトコル/経路を確認して検証環境で更新を比較

DNSと名前解決設定を確認する

名前解決失敗の各カウンタとSUM_CONNECT_ERRORSは分けて読みます。「DNS失敗はすべて遮断対象のハンドシェイクエラー」とは扱いません。下のskip-name-resolveはアカウント照合にも影響する起動設定の旧例で、原因未確認のまま有効化しません。

# my.cnf
[mysqld]
skip-name-resolve

次のDROP USER/CREATE USER/GRANT ALLは実行しない旧例です。 名前解決方式を変えると既存アカウントのHost条件へ影響しますが、先に既存ユーザーを削除したり、%で接続範囲を広げたりする手順にはしません。secretは例示値で使用不可。必要なら実際の照合条件・最小権限・保守接続の確保を伴う別計画にします:

-- 旧(ホスト名)
DROP USER 'app'@'app-server.example.com';

-- 新(IP / ワイルドカード)
CREATE USER 'app'@'10.0.1.%' IDENTIFIED BY 'secret';
GRANT ALL ON myapp.* TO 'app'@'10.0.1.%';
FLUSH PRIVILEGES;

クラウド DB(RDS / Aurora)でブロックされた場合

RDS/Auroraはエンジンの版とサービス側の権限・管理操作を確認します。同じVPCから接続できるだけで管理SQLを実行できるわけではありません。下は一律の順次実行手順ではなく、再起動やパラメータ変更を最初の解除方法にしません:

  1. 許可済みの管理接続とエンジン固有の解除方法を確認し、観測情報を記録する
  2. パラメータの実効値と接続不良の原因を照合。増量を恒久対策としない
  3. 管理経路が使えない場合は運用担当へ連絡。再起動は可用性/接続断の影響を確認する別作業

アプリ側の予防策

下の「OK」は完成した再試行実装ではありません。 旧例は認証失敗等も無差別に再試行し、jitterや総時間制限がありません。接続失敗すべてが遮断カウンタを消費するというコメントも誤りです。5回は最大試行数で待機は通常1/2/4/8秒の4回、16秒は実行されません。1129・認証不良・期限切れは闇雲に再試行せず停止/通知し、一時的な接続障害だけを設計済みの上限で扱います。

<?php
// ❌ NG: 無限リトライ
while (true) {
    try {
        $pdo = new PDO("mysql:host=db;dbname=app", $user, $pass);
        break;
    } catch (PDOException $e) {
        // 即座に再接続 → max_connect_errors を一瞬で食いつぶす
    }
}

// ✅ OK: 指数バックオフ + 上限
$maxRetries = 5;
for ($i = 0; $i < $maxRetries; $i++) {
    try {
        $pdo = new PDO("mysql:host=db;dbname=app", $user, $pass);
        break;
    } catch (PDOException $e) {
        if ($i === $maxRetries - 1) throw $e;
        sleep(2 ** $i);  // 1, 2, 4, 8, 16 秒
    }
}

関連する設定変数

変数既定値役割
max_connect_errors100ブロック閾値
connect_timeout10ハンドシェイク待ち秒
max_connections151同時接続上限
host_cache_sizeautoホストキャッシュ容量
skip_name_resolveOFFDNS 逆引き無効化

FAQ

Q: 自分の IP がブロックされたら自分自身では解除できない?
A: 遮断された接続元以外の、許可された管理経路が必要です。Unixソケット/ループバックはホストキャッシュの対象外ですが、SSH権限だけでDB管理権限が得られるわけではありません。版別の解除方法と権限を確認します。

Q: 再起動でブロックは消える?
A: 再起動でメモリ上のキャッシュは失われますが、接続断と停止の影響があります。診断情報も消えるため解除の初手にせず、発生元の接続不良を直さなければ再発し得ます。

Q: max_connect_errors を 0 にしたら無制限?
A: 無制限化や最大値への増量を推奨しません。対象版の許容範囲と実効値を確認し、遮断対象エラーの原因を先に調べます。max_connectionsやアカウント単位の失敗ログイン追跡とも別です。

ほかの症状はMySQLエラー一覧の子ページから選んでください。ソケット認証1698、期限切れ1820/1862とは条件を分けて調べます。

子ページ

子ページはありません

同階層のページ
  1. 1071 Specified key was too long; max key length is 767 bytes
  2. ERROR 1063 (42000): Incorrect column specifier for column '~'
  3. mysqld: Can't change dir to '...\MySQL\MySQL Server X.X\data\' (OS errno 2 - No such file or directory)
  4. Install/Remove of the Service Denied!
  5. Datetime 型が NULL に見える
  6. Warning: World-writable config file '/etc/mysql/my.cnf' is ignored
  7. ERROR 1698 (28000): Access denied for user 'root'@'localhost'
  8. Exception: Wrong MySQL configuration
  9. [Warning] TIMESTAMP with implicit DEFAULT value is deprecated.
  10. ERROR 1820 (HY000): You must reset your password using ALTER USER statement before executing this statement.
  11. ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
  12. Incorrect column specifier for column 'カラム名'
  13. BLOB/TEXT column 'description' used in key specification without a key length
  14. ERROR: /bin/sh: mysql_config: コマンドが見つかりません
  15. Host '...' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'
  16. CSVエクスポート時に「ERROR 1045 (28000): Access denied for user 'username'@'localhost'」エラーが表示される
  17. Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT
  18. SQLSTATE[22007]: Invalid datetime format: 1366 Incorrect string value: ~

最近更新/作成されたページ