症状別 /
データベースが壊れた・クラッシュした ─ 最初の30分でやるべき確認と復旧の判断
MySQLが起動しない、テーブルが壊れたと表示される、ibdata1が破損した。こうしたDBトラブルは最初の動き方で復旧可否が決まる。やるべきこととやってはいけないことを、現場経験から整理した。
<p>「DBがクラッシュしました」という連絡が来る。夜中の2時でも、繁忙期の昼でも、タイミングを選ばずに来る。このとき最初の動き方を間違えると、復旧できたはずのデータが永遠に失われる。焦りが状況を悪化させる典型的な障害だ。</p>
<p>まず確認すべきは「本当に壊れているのか、接続できていないだけなのか」という切り分けだ。この2つは対処がまったく違う。</p>
<p>MySQLで <code>Table './db_name/table_name' is marked as crashed and should be repaired</code> というエラーが出ているなら、テーブルの物理破損だ。MyISAMなら <code>CHECK TABLE</code> → <code>REPAIR TABLE</code> で直ることが多い。InnoDBでこれをやっても意味がない。むしろ傷口を広げる危険がある。InnoDBの場合は手順が全く異なる。</p>
<p>接続エラー(<code>Too many connections</code>、<code>Access denied for user</code>)なら、データ自体は無事の可能性が高い。スロークエリの積み重ねやメモリ不足によるプロセス詰まりを疑う。<code>SHOW PROCESSLIST;</code> で何が走っているか確認し、必要なら <code>KILL QUERY</code> で詰まりを解消する。この段階で慌ててMySQLを再起動すると、進行中のトランザクションが全部ロールバックされて余計な問題が起きる場合がある。</p>
<p>本当にMySQLが起動しない場合は、まず <code>/var/log/mysql/error.log</code>(Xserverなら <code>~/mysql/db_name/mysql_error.log</code>)を開く。ここに答えのほぼ全てが書いてある。</p>
<p><code>InnoDB: Unable to lock ./ibdata1, error: 11</code> はMySQLの二重起動か、前回の異常終了でロックファイルが残っている。<code>InnoDB: File ./ibdata1 was not closed normally</code> はプロセスの強制終了後によく見る表現で、多くの場合は再起動で回復する。<code>InnoDB: Tablespace is marked as corrupt</code> になると話が違う。深刻な破損の可能性がある。</p>
<p>ここで絶対にやってはいけない操作がある。<strong><code>ibdata1</code> や <code>ib_logfile0</code>、<code>ib_logfile1</code> を削除しない</strong>。StackOverflowやQiitaに「消してしまえ」という回答が散見されるが、あれは特定の文脈(データを捨てて再構築してよい場合)に限って有効なのであって、本番データが入った状態でやれば全データが消える。状況を確認せずに実行しないこと。</p>
<p>次に確認するのはバックアップの鮮度だ。最新のバックアップがいつ取られたか。mysqldumpの自動実行ログ、AWS RDSなら自動スナップショット、Xserverなら「バックアップから復元」の選択肢がある。「毎日バックアップされているはず」という思い込みが最も危険で、実際にはcronが止まっていた・ディスクフルで書き込めていなかったというケースが想像以上に多い。</p>
<p>バックアップが確認できた場合、復旧の方針は明快だ。新しいDBサーバを立てて、そこにリストアし、アプリの接続先を切り替える。元の壊れたDBサーバを直そうとするよりずっと速く、リスクも低い。本番でサービスを止められない状況なら、この並行構成が現実的な唯一の選択肢になる。</p>
<p>バックアップがない場合、InnoDBの <code>ibdata1</code> と各テーブルの <code>.ibd</code> ファイルが残っていればデータを抽出できる可能性がある。<code>innodb_force_recovery</code> を <code>my.cnf</code> に設定して1から始め、少しずつ値を上げながら起動を試みる。起動できたら即座に <code>mysqldump</code> か <code>SELECT INTO OUTFILE</code> でデータをエクスポートする。この作業は元のファイルをコピーして別環境でやること。元ファイルを操作しながらやると、取り戻せたはずのデータが消える。</p>
<p><code>innodb_force_recovery=6</code> まで上げても起動しない場合はファイルレベルの破損になり、専用ツール(Percona Data Recovery Tool for InnoDB など)が必要になる。この段階になると自力対応は難しい。費用はかかるが専門業者に依頼した方が回収できるデータ量が多い。</p>
<p>クラウドのマネージドDB(Amazon RDS、Cloud SQL、PlanetScale)を使っていれば、PITR(ポイント・イン・タイム・リカバリ)が使える。RDSであれば5分前の状態まで戻せる。オンプレや共有レンタルサーバで自前運用していると、この選択肢がない。それを思い知らされるのがいつも障害の瞬間だ。</p>
<p>復旧後にやること。根本原因を潰さないと同じことがまた起きる。最もよく見る原因は3つ:ディスクフルによる書き込み失敗、<code>kill -9</code> によるMySQLの強制終了、ファイルシステムの不整合(古いサーバや仮想マシンで特に多い)。<code>df -h</code> でディスク使用率を確認し、MySQLのエラーログを保存して、再発防止の設定を入れる。</p>
<p>監視がなかった場合は、この機会に入れる。MySQLのプロセス生存確認、ディスク使用率のアラート(80%で警告・90%で緊急)、バックアップ完了の通知。DatadogやCloudWatch、あるいは簡単なcronスクリプトで30分もあれば設定できる。</p>
<p>自分で動かせないと判断したら、早めに連絡してほしい。6時間こじらせた後よりも、最初の1時間で相談してもらった方が、復旧できる確率が上がる。破損したファイルを操作すればするほど、取り戻せるデータが減っていく。</p>
<p>まず確認すべきは「本当に壊れているのか、接続できていないだけなのか」という切り分けだ。この2つは対処がまったく違う。</p>
<p>MySQLで <code>Table './db_name/table_name' is marked as crashed and should be repaired</code> というエラーが出ているなら、テーブルの物理破損だ。MyISAMなら <code>CHECK TABLE</code> → <code>REPAIR TABLE</code> で直ることが多い。InnoDBでこれをやっても意味がない。むしろ傷口を広げる危険がある。InnoDBの場合は手順が全く異なる。</p>
<p>接続エラー(<code>Too many connections</code>、<code>Access denied for user</code>)なら、データ自体は無事の可能性が高い。スロークエリの積み重ねやメモリ不足によるプロセス詰まりを疑う。<code>SHOW PROCESSLIST;</code> で何が走っているか確認し、必要なら <code>KILL QUERY</code> で詰まりを解消する。この段階で慌ててMySQLを再起動すると、進行中のトランザクションが全部ロールバックされて余計な問題が起きる場合がある。</p>
<p>本当にMySQLが起動しない場合は、まず <code>/var/log/mysql/error.log</code>(Xserverなら <code>~/mysql/db_name/mysql_error.log</code>)を開く。ここに答えのほぼ全てが書いてある。</p>
<p><code>InnoDB: Unable to lock ./ibdata1, error: 11</code> はMySQLの二重起動か、前回の異常終了でロックファイルが残っている。<code>InnoDB: File ./ibdata1 was not closed normally</code> はプロセスの強制終了後によく見る表現で、多くの場合は再起動で回復する。<code>InnoDB: Tablespace is marked as corrupt</code> になると話が違う。深刻な破損の可能性がある。</p>
<p>ここで絶対にやってはいけない操作がある。<strong><code>ibdata1</code> や <code>ib_logfile0</code>、<code>ib_logfile1</code> を削除しない</strong>。StackOverflowやQiitaに「消してしまえ」という回答が散見されるが、あれは特定の文脈(データを捨てて再構築してよい場合)に限って有効なのであって、本番データが入った状態でやれば全データが消える。状況を確認せずに実行しないこと。</p>
<p>次に確認するのはバックアップの鮮度だ。最新のバックアップがいつ取られたか。mysqldumpの自動実行ログ、AWS RDSなら自動スナップショット、Xserverなら「バックアップから復元」の選択肢がある。「毎日バックアップされているはず」という思い込みが最も危険で、実際にはcronが止まっていた・ディスクフルで書き込めていなかったというケースが想像以上に多い。</p>
<p>バックアップが確認できた場合、復旧の方針は明快だ。新しいDBサーバを立てて、そこにリストアし、アプリの接続先を切り替える。元の壊れたDBサーバを直そうとするよりずっと速く、リスクも低い。本番でサービスを止められない状況なら、この並行構成が現実的な唯一の選択肢になる。</p>
<p>バックアップがない場合、InnoDBの <code>ibdata1</code> と各テーブルの <code>.ibd</code> ファイルが残っていればデータを抽出できる可能性がある。<code>innodb_force_recovery</code> を <code>my.cnf</code> に設定して1から始め、少しずつ値を上げながら起動を試みる。起動できたら即座に <code>mysqldump</code> か <code>SELECT INTO OUTFILE</code> でデータをエクスポートする。この作業は元のファイルをコピーして別環境でやること。元ファイルを操作しながらやると、取り戻せたはずのデータが消える。</p>
<p><code>innodb_force_recovery=6</code> まで上げても起動しない場合はファイルレベルの破損になり、専用ツール(Percona Data Recovery Tool for InnoDB など)が必要になる。この段階になると自力対応は難しい。費用はかかるが専門業者に依頼した方が回収できるデータ量が多い。</p>
<p>クラウドのマネージドDB(Amazon RDS、Cloud SQL、PlanetScale)を使っていれば、PITR(ポイント・イン・タイム・リカバリ)が使える。RDSであれば5分前の状態まで戻せる。オンプレや共有レンタルサーバで自前運用していると、この選択肢がない。それを思い知らされるのがいつも障害の瞬間だ。</p>
<p>復旧後にやること。根本原因を潰さないと同じことがまた起きる。最もよく見る原因は3つ:ディスクフルによる書き込み失敗、<code>kill -9</code> によるMySQLの強制終了、ファイルシステムの不整合(古いサーバや仮想マシンで特に多い)。<code>df -h</code> でディスク使用率を確認し、MySQLのエラーログを保存して、再発防止の設定を入れる。</p>
<p>監視がなかった場合は、この機会に入れる。MySQLのプロセス生存確認、ディスク使用率のアラート(80%で警告・90%で緊急)、バックアップ完了の通知。DatadogやCloudWatch、あるいは簡単なcronスクリプトで30分もあれば設定できる。</p>
<p>自分で動かせないと判断したら、早めに連絡してほしい。6時間こじらせた後よりも、最初の1時間で相談してもらった方が、復旧できる確率が上がる。破損したファイルを操作すればするほど、取り戻せるデータが減っていく。</p>
この症状でお困りなら、まず無料相談
60分無料相談を予約