MySQL接続エラーの解消:1045から「Too Many Connections」まで — 実践的なトラブルシューティング

MySQL tutorial - IT technology blog
MySQL tutorial - IT technology blog

MySQLが「ストライキ」:SysAdminたちの眠れない夜

ある日の午前2時、システム監視をしていた時のことを鮮明に覚えています。顧客のウェブサイトが突然ダウンし、「Error establishing a database connection」という文字が表示されました。キーボードを叩く音よりも速く心臓が鼓動していました。調査の結果、コードのリークによる Too many connections エラーであることが判明しました。このような「火消し」の経験から学んだのは、パニックにならず、正しい場所から点検を始めることの大切さです。

データを破損(corrupt data)させる恐れがあるため、すぐにサーバーを再起動してはいけません。代わりに、具体的な症状から冷静に「診断」し、最も正確な解決策を導き出しましょう。

MySQLトラブル発生時の2つのアプローチ

通常、ITエンジニアが接続エラーに直面した際、次のいずれかの方法を選択します。

  • 方法1:応急処置(消火活動): MySQLの再起動、ロックファイルの削除、あるいは根拠なく設定値を上げること。この方法はシステムを即座に復旧させますが、根本的な解決にはなりません。最悪の場合、ディスクに書き込まれていないバッファ内のデータを失う可能性もあります。
  • 方法2:原因分析(Root Cause Analysis): エラーログの確認、ネットワークやユーザー権限のチェック。最初は少し時間がかかりますが、システムの長期的な安定につながります。

私は常に方法2を優先します。システムが完全に停止し、一時的に「息を吹き返させる」必要がある場合にのみ、サービスを維持するために方法1を使います。

1. Error 1045 (28000):認証情報の誤り、またはアクセス拒否

これは最も一般的なエラーです。パスワードの間違いや、現在のホストからのアクセス権限がない場合に発生します。正しいパスワードを入力していても、MySQLが 'root'@'localhost''root'@'127.0.0.1' を厳密に区別しているためにブロックされることがあります。

解決方法:

もしrootパスワードを忘れてしまった場合は、MySQLを skip-grant-tables モードで起動してリセットします。

# サービスを停止
sudo systemctl stop mysql

# パスワードなしで一時起動
sudo mysqld_safe --skip-grant-tables &

# ログインして新しいパスワードに変更
mysql -u root
FLUSH PRIVILEGES;
ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewPassword@2024';

注意: mysql データベース内の user テーブルを確認してください。 host カラムが、 localhost だけでなく、適切なIPからの接続を許可しているか確認しましょう。

2. Error 2002 (HY000):ソケットエラー、またはMySQLが未起動

このエラーは通常、クライアントが .sock ファイルを見つけられない場合に発生します。MySQLの突然のクラッシュや、ディスク容量がいっぱいでサービスが起動できないことが原因です。

解決方法:

まず、サービスの状態を確認します:

sudo systemctl status mysql

サービスが起動しているのにエラーが出る場合は、 my.cnf 設定ファイル内のソケットファイルの場所を確認します:

grep -r "socket" /etc/mysql/

痛い教訓:常に df -hdf -i コマンドを使用しましょう。以前、1時間も悩んだ末にサーバーのiノード(Inodes)が枯渇していたことに気づきました。ディスク容量があっても、MySQLがソケットファイルを作成できなくなっていたのです。

3. Error 1130 (HY000):リモート接続の拒否

MySQLはセキュリティ上、デフォルトでlocalhostのみをリッスン(listen)します。個人のPCから DBeaver や Navicat などのツールで接続したい場合は、この設定を変更する必要があります。

解決手順:

  1. 設定の修正: mysqld.cnf ファイルを開き、 bind-address 行を探します。 127.0.0.1 から 0.0.0.0 に変更します。
  2. ユーザー権限の付与: SQLを実行して、外部IPからの接続を許可します。
-- ユーザー 'dev_user' に全IPからの接続を許可(rootには非推奨)
CREATE USER 'dev_user'@'%' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON database_name.* TO 'dev_user'@'%';
FLUSH PRIVILEGES;

セキュリティのヒント: rootユーザーに対して '%' を使用しないでください。AWSやGoogle Cloudを使用している場合は、Security GroupやFirewallでポート3306を忘れずに開放してください。

4. 「Too many connections」エラー

これはシステムをスケールさせる際の悪夢です。MySQLのデフォルトの同時接続数は151です。各接続は約2MB〜10MBのRAMを消費します。むやみに増やすと、メモリ不足でサーバーがハングアップします。

根本的な解決:

すぐに max_connections を増やさないでください。まずは何がリソースを占有しているか確認しましょう:

SHOW PROCESSLIST;

もし何百もの接続が「Sleep」状態であれば、アプリケーションのコネクションプーリング(Connection Pooling)に問題があります。待ち時間を短縮して、MySQLが不要な接続を自動的に切断するように設定しましょう:

-- my.cnf での設定
[mysqld]
max_connections = 500
wait_timeout = 60
interactive_timeout = 60

秒間5000リクエストを処理するプロジェクトでは、ProxySQL を仲介役として導入しました。これにより接続の再利用が非常に効率的になり、ハードウェアをアップグレードすることなくMySQLの負荷を40%削減できました。

迅速な診断のためのチェックリスト

システムが接続エラーを報告するたびに、私はいつも以下の5つのステップを素早く確認します:

  1. ネットワーク: サーバーにPingが通りますか? ポート3306がファイアウォールでブロックされていませんか?
  2. サービス: systemctl status mysql コマンドの結果は正常(緑)ですか?
  3. ログ: /var/log/mysql/error.log の末尾100行を確認してください。原因の90%はここにあります。
  4. リソース: RAMがスワップ(swap)していませんか? ディスクの空き容量はありますか?
  5. 権限: ユーザーはそのIPからの接続権限を持っていますか?

エラーコードを理解していれば、一晩中悩む代わりに5分で問題を解決できます。データベース管理がスムーズに進み、深夜の緊急電話に悩まされることがなくなるよう願っています!

Share: