mysqlbinlogでMySQLをポイントインタイムリカバリする方法|誤操作直前まで戻す復旧手順

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)Linuxtipsデーターベース管理 > mysqlbinlogでMySQLをポイントインタイムリカバリする方法|誤操作直前まで戻す復旧手順
「昨夜のバッチがWHERE句なしでDELETE文を実行してしまった」「開発者がうっかりDROP TABLEを本番で実行した」——こんな連絡が深夜に来たとき、手元にバイナリログとフルバックアップがあれば、誤操作の直前まで巻き戻すことができます。

この記事では、mysqlbinlogコマンドを使ったMySQLのポイントインタイムリカバリ(PITR)の手順を、実際のコマンド出力とともに解説します。フルバックアップのリストアを基点に、バイナリログから誤操作直前のポジションを特定し、差分を再適用するまでの一連の流れを網羅します。

実行環境:MySQL 8.0.36 / Rocky Linux 9.4 で動作確認済み。MySQL 5.7でも基本手順は同じです。

この記事のポイント

・mysqlbinlog + フルバックアップで誤操作直前まで復旧できる
・--stop-position でDROP/DELETE文だけをスキップして再適用できる
・バイナリログが期限切れで削除されると復旧不可能になる
・ROW形式のバイナリログ確認には --base64-output=DECODE-ROWS が必要


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

PITRとmysqldumpバックアップの違い

mysqldumpによるフルバックアップ・リストアは「バックアップ取得時点」まで戻す手段です。バックアップ取得後に投入されたデータは消えてしまいます。

これに対してポイントインタイムリカバリ(PITR)は、フルバックアップのリストアを「起点」として、そこからバイナリログに記録されたトランザクションを順番に再適用することで、任意の時刻・ポジションまでデータを復元します。

たとえば「昨日22:00のバックアップ後、今日11:57:42に誤操作が起きた」場合、バックアップから11:57:41までのバイナリログを適用すれば、誤操作の1秒前の状態に戻せます。

mysqldumpでのフルバックアップ・リストアが基点になるため、両方の手順を把握しておくことが重要です。

前提条件:バイナリログの有効化を確認する

PITRにはバイナリログが必須です。まずMySQLにログインして有効かどうか確認してください。

1. バイナリログが有効かどうか確認する

mysql -u root -p -e "SHOW VARIABLES LIKE 'log_bin';"

実際の出力:

+---------------+-------+ | Variable_name | Value | +---------------+-------+ | log_bin | ON | +---------------+-------+

log_bin = OFF の場合、/etc/my.cnf(または /etc/mysql/mysql.conf.d/mysqld.cnf)に以下を追加してMySQLを再起動してください。

[mysqld] log_bin = /var/lib/mysql/mysql-bin server_id = 1 # MySQL 8.0以降。5.7は expire_logs_days で設定する binlog_expire_logs_seconds = 604800

重要: binlog_expire_logs_secondsの値が小さすぎるとバイナリログが削除されてPITRが不可能になります。本番環境では最低7日以上(604800秒)を推奨します。

2. バイナリログ形式を確認する

mysql -u root -p -e "SHOW VARIABLES LIKE 'binlog_format';"

+---------------+-------+ | Variable_name | Value | +---------------+-------+ | binlog_format | ROW | +---------------+-------+

MySQL 8.0のデフォルトはROW形式です。ROW形式は行単位で変更内容を記録するため、PITRの信頼性が高くなります。STATEMENT形式ではNOW()RAND()などの非決定的関数を含むSQL文を再適用した際に結果が変わる可能性があり、本番復旧には向きません。

基本的なPITR手順

1. フルバックアップを基点として復元する

まず直近のmysqldumpバックアップをリストアします。同時に、ダンプに記録されたバイナリログのポジション情報を確認します。

# バックアップファイルを確認 ls -lh /backup/mysql/ # -rw-r--r-- 1 root root 2.3G Aug 18 03:00 full_backup_20260818.sql.gz # ダンプの先頭でバイナリログ情報を確認 zcat /backup/mysql/full_backup_20260818.sql.gz | head -50 | grep -E 'MASTER_LOG|binlog' # -- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000042', MASTER_LOG_POS=157;

MASTER_LOG_FILEMASTER_LOG_POSが復旧開始点です。この情報はmysqldump実行時に--master-data=2(MySQL 8.4以降は--source-data=2)を付けた場合にのみ記録されます。付け忘れていた場合はダンプ時刻を目安に手動でポジションを調べる必要があります。

次にリストアを実行します。

# リストア(時間がかかるため画面から切れないようにscreenかtmux内で実行) zcat /backup/mysql/full_backup_20260818.sql.gz | mysql -u root -p

2. バイナリログファイルの一覧を確認する

リストア後、バックアップ取得時点以降のバイナリログを確認します。

mysql -u root -p -e "SHOW BINARY LOGS;"

+------------------+-----------+-----------+ | Log_name | File_size | Encrypted | +------------------+-----------+-----------+ | mysql-bin.000042 | 54332172 | No | | mysql-bin.000043 | 98765432 | No | | mysql-bin.000044 | 3456789 | No | +------------------+-----------+-----------+

バックアップに記録されていたmysql-bin.000042の157番ポジション以降が適用対象です。ファイルの保存場所はMySQL設定のlog_binで指定したパスか、SHOW VARIABLES LIKE 'log_bin_basename'で確認できます。

3. 誤操作の日時・ポジションを特定する

mysqlbinlogで問題のSQLが記録されているポジションを探します。ROW形式のバイナリログはそのまま表示するとBase64になるため、--base64-output=DECODE-ROWS -vvを付けて人間が読める形式に変換します。

mysqlbinlog --base64-output=DECODE-ROWS -vv \ /var/lib/mysql/mysql-bin.000044 | grep -B 5 -A 5 "DROP TABLE\|DELETE FROM"

実際の出力例(誤操作がmysql-bin.000044のポジション892471に記録されている場合):

# at 892471 #260818 11:57:42 server id 1 end_log_pos 892612 CRC32 0x4b2f1a3c Query thread_id=8 exec_time=0 error_code=0 SET TIMESTAMP=1755478662/*!*/; DROP TABLE `orders` /*!*/;

誤操作のポジションは892471、時刻は2026-08-18 11:57:42と判明しました。復旧の終了点は--stop-position=892471で指定します(892471のイベント自体は含まれず、直前で止まります)。

4. mysqlbinlogで差分SQLを生成して適用する

バックアップの開始ポジション(157)から誤操作のポジション(892471)の直前までのトランザクションを再適用します。

# バックアップ取得後の最初のファイルから中間ファイルまで全件適用 mysqlbinlog \ --start-position=157 \ /var/lib/mysql/mysql-bin.000042 \ /var/lib/mysql/mysql-bin.000043 | mysql -u root -p # 最後のファイルは誤操作ポジションで停止(そのポジション自体は含まれない) mysqlbinlog \ --stop-position=892471 \ /var/lib/mysql/mysql-bin.000044 | mysql -u root -p

適用後、対象テーブルのレコード数を確認して復旧結果を検証してください。

mysql -u root -p -e "SELECT COUNT(*) FROM mydb.orders;" # +----------+ # | COUNT(*) | # +----------+ # | 14823 | # +----------+

応用:特定の誤操作だけをスキップして残りを復旧する

DROP/DELETEだけをスキップして、それ以降に行われた正常なトランザクションも含めて復旧したい場合は、誤操作ポジションの直前と直後に分けて2回適用します。

1. 誤操作直後のポジションを確認してから再適用する

# 誤操作イベントの end_log_pos(出力例では892612)の次のポジションを確認 mysqlbinlog --base64-output=DECODE-ROWS -vv \ /var/lib/mysql/mysql-bin.000044 | grep "^# at" | grep -A 1 "892612" # # at 892613 # 892613以降(誤操作の直後)から最新まで適用 mysqlbinlog \ --start-position=892613 \ /var/lib/mysql/mysql-bin.000044 | mysql -u root -p

2. 日時指定で適用する方法(--start-datetime / --stop-datetime)

ポジション番号が分からない場合、日時で指定することもできます。ただし日時指定は1秒単位のため、同じ秒内に複数のトランザクションがある環境では誤操作を含んでしまう可能性があります。ポジション指定の方が確実です。

# 日時指定の例(誤操作が 2026-08-18 11:57:42 の場合、その1秒前で停止) mysqlbinlog \ --start-datetime="2026-08-18 03:00:00" \ --stop-datetime="2026-08-18 11:57:41" \ /var/lib/mysql/mysql-bin.000042 \ /var/lib/mysql/mysql-bin.000043 \ /var/lib/mysql/mysql-bin.000044 | mysql -u root -p

トラブルシュート

「ROW形式でSQL文の内容が読めない」

ROW形式のバイナリログをオプションなしでmysqlbinlogに通すと、DML(INSERT/UPDATE/DELETE)の内容はBase64エンコードされたまま表示されます。

# オプションなし → Base64のまま(内容を確認できない) mysqlbinlog /var/lib/mysql/mysql-bin.000044 | grep -A 3 "BINLOG" # BINLOG ' # 3xKuZBMBAAAALgAAAKcBAAAAACQAAAAAAAEABm15ZGJiBgBvcmRlcnMM... # --base64-output=DECODE-ROWS -vv を付けると確認できる mysqlbinlog --base64-output=DECODE-ROWS -vv \ /var/lib/mysql/mysql-bin.000044 | grep -A 5 "DELETE"

注意: --base64-output=DECODE-ROWSで出力した内容はコメント扱いになるため、実際のリストア(mysql -u root -p への適用)には使えません。ポジション確認専用のオプションです。リストア実行時はこのオプションを付けずに実行してください。

「unknown variable 'default-character-set=utf8mb4'」エラーが出る

/etc/my.cnf[client]セクションにdefault-character-setが設定されていると、mysqlbinlogが解釈できずにエラーになります。

# --no-defaults を付けてmy.cnfを読み込まないようにする mysqlbinlog --no-defaults \ --stop-position=892471 \ /var/lib/mysql/mysql-bin.000044 | mysql --no-defaults -u root -p

バイナリログが削除済みで復旧できないケース

SHOW BINARY LOGSで表示されるファイルが、バックアップ時点のMASTER_LOG_FILEより新しい場合、途中のログが失われています。この状態では差分の完全な適用はできません。

# バックアップに記録されたファイル: mysql-bin.000042 # 現在残っているログを確認 mysql -u root -p -e "SHOW BINARY LOGS;" # mysql-bin.000045 から始まる場合 # → 000042~000044 が削除済み → PITRは不可

binlog_expire_logs_secondsの設定値を見直し、フルバックアップの間隔よりも長い保持期間を確保してください。バックアップとセットで設計してこそPITRは機能します。

本記事のまとめ

やりたいこと コマンド・設定
バイナリログの有効化確認 SHOW VARIABLES LIKE 'log_bin'
バイナリログ一覧の確認 SHOW BINARY LOGS
ROW形式のSQL内容を確認 mysqlbinlog --base64-output=DECODE-ROWS -vv mysql-bin.XXXXXX
ポジション指定で差分を適用 mysqlbinlog --start-position=N mysql-bin.XXXXXX | mysql -u root -p
誤操作直前で停止して適用 mysqlbinlog --stop-position=N mysql-bin.XXXXXX | mysql -u root -p
日時指定で差分を適用 mysqlbinlog --stop-datetime="YYYY-MM-DD HH:MM:SS" mysql-bin.XXXXXX | mysql -u root -p
ログ保持期間の設定(8.0以降) binlog_expire_logs_seconds = 604800(my.cnf)
PITRはバイナリログが存在して初めて成立する復旧手段です。フルバックアップと合わせて「バイナリログを必ず保持する運用設計」を今日から始めておくと、いざというときに選択肢を失わずに済みます。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、20年以上の運用経験を持つ現役エンジニアがPITRを含むMySQLバックアップ運用の実践スキルを教えます。
Linux Master Pro Seminar の詳細を見る >>

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。