エラーログには「InnoDB: Corruption」「Page read failed」の文字が並んでいる。バックアップはあるが2日前のもので、その間に処理したデータをそのまま捨てることにはなかなか踏み切れない。こうした事態は突然やってきます。
この記事では、MySQL 8.0系/MariaDB 10.6系を想定環境として、InnoDB障害でMySQLが起動しなくなった場合に
innodb_force_recovery を使ってデータを救出・復旧する手順を解説します。エラーログの読み方から、mysqldumpによるデータ抽出、新規インスタンスへの再インポートまでをステップごとに説明します。この記事のポイント
・innodb_force_recoveryは値1から始め、起動できたら即mysqldumpを取る
・値4以上になるとDMLが禁止され、データ欠損のリスクが急に高まる
・復旧後は必ずinnodb_force_recoveryを削除し、新規DBへ再インポートする
・エラーログの確認が最初のステップ(RHEL系は/var/log/mysqld.log)
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
なぜInnoDBクラッシュでMySQLが起動しなくなるのか
MySQLのデフォルトストレージエンジンであるInnoDBは、トランザクション整合性を保つためにデータファイル(.ibd)とログファイル(ib_logfile)をペアで管理しています。正常な停止であればログを適切に閉じてからシャットダウンしますが、以下のようなケースでは書き込み途中のままファイルが閉じられ、次回起動時に不整合が検出されます。・OSの強制終了やサーバー電源断(UPSなし環境で多い)
・OOM Killerによるmysqldプロセスの強制終了
・ディスクの物理的な障害(バッドセクタ)
・ファイルシステムのエラー(ext4・XFSのジャーナル破損)
起動時にInnoDBがデータファイルの不整合を検出すると、安全のため起動を拒否します。エラーログには次のようなメッセージが残ります。
# よく見られるInnoDB障害のエラーメッセージ例(環境により異なります) [ERROR] InnoDB: Corruption in the InnoDB tablespace [ERROR] InnoDB: Trying to access page number X in space Y [ERROR] InnoDB: Page [page id: space=5, page number=1234] read failed with error [ERROR] InnoDB: Unable to open tablespace '/var/lib/mysql/mydb/orders.ibd' [ERROR] Plugin 'InnoDB' init function returned error [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed
innodb_force_recovery を使って強制的に起動し、データを救出します。innodb_force_recoveryの設定値と安全な選択基準
innodb_force_recovery は、MySQLの設定ファイル(my.cnf)の [mysqld] セクションに記述する整数値です。0が通常動作で、1~6の数値を設定することで、起動時のInnoDBチェックを段階的に緩和します。| 値 | 動作の変化 | データへの影響 |
|---|---|---|
| 1 | 破損ページを検出しても無視してストレージエンジンを起動する | 低。まずここから試す |
| 2 | バックグラウンドスレッド(mainスレッド・purgeスレッド)を無効化 | 低。purgeが止まるが読み取りは可 |
| 3 | クラッシュリカバリ後のトランザクションロールバックを無効化 | 低~中。未コミットデータが残る場合あり |
| 4 | 挿入バッファ(Insert Buffer)のマージを無効化。書き込み操作(DML)が禁止される | 中。インデックスが不完全になる可能性 |
| 5 | UNDOログを無視して起動 | 高。未コミットデータが混入する場合あり |
| 6 | REDOログを無視して起動。最後の手段 | 最高。データ欠損が起きる可能性がある |
段階的にMySQLを復旧する手順
1. エラーログで障害の種類を特定する
最初にエラーログを確認し、何が原因で起動を拒否しているのかを把握します。# RHEL/CentOS/Rocky Linux/AlmaLinux 系のエラーログ確認 tail -200 /var/log/mysqld.log | grep -i 'error\|innodb\|abort' # Ubuntu/Debian 系の確認先 tail -200 /var/log/mysql/error.log | grep -i 'error\|innodb\|abort' # ログファイルの場所をmy.cnfで確認する方法 grep log_error /etc/my.cnf /etc/mysql/mysql.conf.d/mysqld.cnf 2>/dev/null
2. innodb_force_recoveryを設定してMySQLを起動する
エラーログでInnoDB障害を確認したら、my.cnfを編集します。# /etc/my.cnf または /etc/mysql/mysql.conf.d/mysqld.cnf を編集 # [mysqld] セクションに追記する [mysqld] innodb_force_recovery = 1
systemctl start mysqld systemctl status mysqld
systemctl stop mysqld → my.cnf を編集 → systemctl start mysqld の順で操作してください。できる限り3以下で起動することを目指します。値3以下で起動できた場合は、次のステップに進みます。値4以上でしか起動できない場合は、mysqldumpの一部オプションが機能しない点を念頭に置いてください(後述)。
3. mysqldumpでデータをエクスポートする
MySQLが起動した直後、追加の操作をする前にすぐにデータをダンプします。innodb_force_recoveryで動いている間は障害状態が続いているため、長時間この状態を維持するのは危険です。# 全データベースを一括ダンプ(innodb_force_recovery = 1~3 の場合) mysqldump -u root -p \ --all-databases \ --single-transaction \ --skip-lock-tables \ --routines \ --triggers \ > /tmp/all_dbs_rescue.sql # ダンプファイルのサイズを確認 ls -lh /tmp/all_dbs_rescue.sql # 先頭行でCREATE DATABASEが含まれているか確認 head -30 /tmp/all_dbs_rescue.sql
--single-transaction は書き込み操作を伴うため使えません。その場合は次のコマンドで対応します。# innodb_force_recovery = 4 以上の場合(書き込み禁止のため --skip-lock-tables のみ) mysqldump -u root -p \ --all-databases \ --skip-lock-tables \ --routines \ --triggers \ > /tmp/all_dbs_rescue.sql
systemctl stop mysqld
4. データディレクトリを初期化してインポートする
ダンプが取れた後は、破損したInnoDBファイルが残る既存のデータディレクトリを使い続けることは避けます。新規のデータディレクトリを作成してインポートします。まず、my.cnfから
innodb_force_recovery の設定を削除します。# [mysqld] セクションから以下の行を削除またはコメントアウト # innodb_force_recovery = X ← この行を削除する
# 破損した旧データディレクトリを退避(削除しない) mv /var/lib/mysql /var/lib/mysql.broken # 新しいデータディレクトリを作成 mkdir -p /var/lib/mysql chown mysql:mysql /var/lib/mysql chmod 750 /var/lib/mysql # SELinuxが有効な環境ではラベルを設定する(RHEL系) restorecon -R /var/lib/mysql # InnoDBを初期化 mysqld --initialize --user=mysql --datadir=/var/lib/mysql
# 一時パスワードを確認 grep 'temporary password' /var/log/mysqld.log | tail -1 # 出力例(環境により異なります) # [Note] A temporary password is generated for root@localhost: Ab1Cd2Ef3G!
# MySQL起動 systemctl start mysqld # 一時パスワードでログイン mysql -u root -p
-- 一時パスワード変更(MySQLのパスワードポリシーに合わせた文字列を指定する) ALTER USER 'root'@'localhost' IDENTIFIED BY 'YourNewSecurePass123!'; FLUSH PRIVILEGES; EXIT;
# ダンプをインポート(新パスワードで実行) mysql -u root -p < /tmp/all_dbs_rescue.sql # インポート完了後にデータベース一覧を確認 mysql -u root -p -e "SHOW DATABASES;"
復旧後に必ずやること
インポートが完了してMySQLが通常動作に戻ったら、以下の確認と後片付けを行います。テーブルの整合性チェック
# 全データベース・全テーブルのチェック mysqlcheck -u root -p --all-databases --check # 問題が見つかった場合は修復を試みる mysqlcheck -u root -p --all-databases --repair
データを新規DBに再インポートした時点でバイナリログの連続性は途切れます。MySQLのレプリケーションを構成している場合は、スレーブ側の再設定が必要です。バイナリログのポジションやGTIDを記録しておきます。
-- 現在のバイナリログ位置を確認 SHOW MASTER STATUS\G -- バイナリログの一覧 SHOW BINARY LOGS;
復旧後1週間程度は
/var/lib/mysql.broken を保管し、問題がなければ削除します。なお、ディスクの物理障害が原因だった場合は、ディスクそのものを交換しないと再発します。dmesg やRAIDのイベントログでハードウェアの状態も確認してください。Linuxサーバーでデータベースを安全に自前運用するノウハウをより体系的に身につけたい場合は、Linux Master Pro Seminarでハンズオン形式で学べます。
「それでも起動しない」時の対処法
innodb_force_recovery = 6 に設定しても起動しない場合は、InnoDB以外の問題が重なっている可能性があります。以下の点を順に確認します。ディスク容量の確認
# ディスク使用量の確認 df -h # /var/lib/mysql のinode使用率も確認 df -i /var/lib/mysql
ハードウェア障害の確認
# カーネルのディスクエラーを確認 dmesg | grep -i 'error\|fail\|bad\|reset' # ディスクの健全性確認(smartmontools が必要) smartctl -a /dev/sda
# SELinuxの状態確認 getenforce # mysqlに関するAVC拒否ログの確認 ausearch -c mysqld -m avc 2>/dev/null | tail -20
restorecon -R /var/lib/mysql を実行してラベルを修正します。ファイル権限の確認
# データディレクトリの権限と所有者を確認 ls -la /var/lib/ | grep mysql ls -la /var/lib/mysql/ | head -20 # 正しい状態の例(環境により異なります) # drwxr-x--- 7 mysql mysql 4096 Nov 5 13:00 mysql
本記事のまとめ
innodb_force_recovery は、InnoDB障害でMySQLが起動しなくなった場合のデータ救出ツールです。値を低く抑えながら段階的に試し、起動できた瞬間にmysqldumpを取る——この2点が復旧成功のカギです。| やりたいこと | コマンド/設定 |
|---|---|
| エラーログを確認する | tail -200 /var/log/mysqld.log | grep -i error |
| innodb_force_recoveryを設定する | my.cnfの[mysqld]に innodb_force_recovery = 1 を追記 |
| MySQL起動を確認する | systemctl start mysqld && systemctl status mysqld |
| 全DBをダンプする(値3以下) | mysqldump -u root -p --all-databases --single-transaction > /tmp/rescue.sql |
| 全DBをダンプする(値4以上) | mysqldump -u root -p --all-databases --skip-lock-tables > /tmp/rescue.sql |
| データディレクトリを初期化する | mysqld --initialize --user=mysql --datadir=/var/lib/mysql |
| 一時パスワードを確認する | grep 'temporary password' /var/log/mysqld.log |
| ダンプをインポートする | mysql -u root -p < /tmp/rescue.sql |
| テーブルの整合性チェック | mysqlcheck -u root -p --all-databases --check |
mysqldumpやxtrabackupによる定期バックアップ、バイナリログの有効化を組み合わせておけば、最悪の事態での復旧範囲を最小限に抑えられます。バックアップと復旧テストの定期実施は、本番DBサーバー運用の基本です。
>> Linux Master Pro Seminar の詳細を見る
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:MySQLのLOAD DATA INFILEでCSVを高速インポートする方法|secure-file-privの設定とエラー対処まで
- この記事の属するカテゴリ:データーベース管理へ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます