エラーの内容
アプリやリモートホストからMySQLに接続しようとすると、以下のエラーが表示されます:
ERROR 1129 (HY000): Host '192.168.1.10' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'
MySQLが接続エラーを連続して多数検出したため、そのホストをブロックしました。ホストがmax_connect_errorsの閾値を超えると、MySQLはそのIPをブラックリストに登録します。手動でブロックを解除するか、サーバーを再起動するまで、そのIPからの接続は拒否されます。
発生する原因
クライアントが接続を試みたものの、ネットワークの切断、ハンドシェイクの中断、クライアントの設定ミスなどにより認証が完了する前に失敗するたびに、MySQLはそのホストの内部カウンターを増加させます。max_connect_errorsの上限(デフォルト:100)に達すると、MySQLはそのホストへの接続を遮断します。
よくある原因:
- 接続中にアプリが再起動またはクラッシュし、半開きのTCPソケットが残る
- アプリサーバーとデータベース間のネットワーク不安定
- 障害発生時に接続プールが過度に積極的な再接続を試みる
- MySQLがハンドシェイクを完了する前にファイアウォールやロードバランサーが接続を切断する
- SSL/TLSネゴシエーションに問題のある古いMySQLクライアントライブラリ
ステップ1 — 今すぐホストのブロックを解除する
まず最初に、ホストキャッシュをフラッシュしてアクセスを回復します。3つの方法があります:
方法A: mysqladminを使用する
mysqladmin -u root -p flush-hosts
方法B: MySQLセッション内から実行する
-- ブロックされていないlocalhostからrootで接続する
mysql -u root -p
-- 次のコマンドを実行:
FLUSH HOSTS;
方法C: MySQL 8.0.26以降のみ — performance_schemaテーブルをトランケートする
TRUNCATE TABLE performance_schema.host_cache;
いずれの方法でも、ブロックされているすべてのホストのエラーカウンターがリセットされます。いずれか1つを実行してから接続を再試行すると、すぐに接続できるようになります。
ステップ2 — 接続が失敗していた原因を特定する
ホストのフラッシュは一時的な解決策です。根本原因を修正しなければ、ブロックが再発します。負荷の高いアプリサーバーでは数分以内に再発することもあります。MySQLのエラーログから確認しましょう:
# Ubuntu/Debianのデフォルトの場所
tail -100 /var/log/mysql/error.log
# CentOS/RHELの場合
tail -100 /var/log/mysqld.log
# ログの場所が不明な場合
SHOW VARIABLES LIKE 'log_error';
Aborted connection、Got an error reading communication packets、またはGot timeout reading communication packetsを検索します。これらの行が失敗した接続を直接示しています。
次に、中断された接続のカウンターを確認します:
SHOW GLOBAL STATUS LIKE 'Aborted_connects';
SHOW GLOBAL STATUS LIKE 'Aborted_clients';
- Aborted_connects — 認証前に失敗した接続。これがERROR 1129のトリガーです。
- Aborted_clients — 接続は成功したが正常に切断されなかった場合。緊急度は低いですが、監視する価値があります。
ステップ3 — max_connect_errorsを引き上げる(暫定措置)
不安定なVPN、積極的なKubernetesのliveness probe、認証できないヘルスチェックなど、頻繁だが無害な中断が発生している場合は、MySQLがすぐにブロックしないよう閾値を引き上げることができます。
再起動なしでライブ設定を変更する:
SET GLOBAL max_connect_errors = 1000000;
my.cnf / my.iniに永続的に設定する:
[mysqld]
max_connect_errors = 1000000
次にMySQLを再起動します:
# Ubuntu/Debian
sudo systemctl restart mysql
# CentOS/RHEL
sudo systemctl restart mysqld
この値を非常に高く設定する、またはMySQL 8.0.36以降で0に設定してブロックを完全に無効化することは、すべてのホストを信頼できる内部ネットワークでは問題ありません。公開サーバーの場合は低めの値に設定してください。
ステップ4 — 接続問題の根本原因を修正する
接続プールが過度に積極的な再接続を試みている場合
多くのフレームワークは起動時に急速な再接続を繰り返してMySQLを叩きます。接続前のpingチェックとリサイクル間隔を追加しましょう。Python SQLAlchemyの場合の設定例:
engine = create_engine(
DATABASE_URL,
pool_pre_ping=True, # 使用前に接続を検証する
pool_recycle=3600, # 1時間後に接続を破棄して新しく作成する
connect_args={"connect_timeout": 10}
)
初期テスト中にプールサイズを縮小すると、プール自体が問題かどうかを切り分けるのに役立ちます。
ネットワークやファイアウォールの問題が疑われる場合
MySQL設定を変更する前に、ブロックされたホストからの生のTCP接続をテストします:
telnet 192.168.1.100 3306
# または
nc -zv 192.168.1.100 3306
接続が切れたりハングする場合は、ネットワーク側の問題です。MySQLの設定変更では解決しません。
SSL/TLSネゴシエーションが問題を引き起こしている場合
# SSLを完全に無効にして接続を試みる
mysql -h 192.168.1.100 -u myuser -p --ssl-mode=DISABLED
SSL無効では接続できるのに通常は失敗する場合は、クライアントライブラリを更新するか、証明書の設定を見直してください。
修正の確認
ホストをフラッシュして根本原因に対処したら、そのIPがブロックされていないことを確認します:
-- MySQL 8.0以降のみ
SELECT host, host_validated, sum_connect_errors, count_host_blocked_errors
FROM performance_schema.host_cache
WHERE host = '192.168.1.10';
sum_connect_errorsが0またはそれに近い値であることを確認します。count_host_blocked_errorsが増加していないことも確認してください。
コマンドラインからの簡単な動作確認:
mysql -h 192.168.1.100 -u myuser -p -e "SELECT 1;"
1が返ってきたら、修正完了です。
再発防止策
- 接続プールで
pool_pre_pingを有効にする — 接続を渡す前に検証するため、MySQLがハンドシェイク中に切断されたソケットを見ることがなくなります wait_timeoutとinteractive_timeoutを調整する — アプリが実際に接続を保持する時間に合わせて設定します- メトリクスで
Aborted_connectsを監視する — スパイクはERROR 1129が発生する数分前の早期警告シグナルです - アプリとMySQLの間にProxySQLまたはHAProxyを配置する — プロキシは再接続ロジックを適切に処理し、再起動時に生のTCP再試行でMySQLを叩くことがありません
- デプロイスクリプトに
FLUSH HOSTSを追加する — リリース時にアプリサーバーが頻繁に再起動する場合、ローリングデプロイ中にブロックが蓄積するのを防ぎます

