この記事では、mysqlbinlogコマンドを使ったMySQLのポイントインタイムリカバリ(PITR)の手順を、実際のコマンド出力とともに解説します。フルバックアップのリストアを基点に、バイナリログから誤操作直前のポジションを特定し、差分を再適用するまでの一連の流れを網羅します。
実行環境:MySQL 8.0.36 / Rocky Linux 9.4 で動作確認済み。MySQL 5.7でも基本手順は同じです。
この記事のポイント
・mysqlbinlog + フルバックアップで誤操作直前まで復旧できる
・--stop-position でDROP/DELETE文だけをスキップして再適用できる
・バイナリログが期限切れで削除されると復旧不可能になる
・ROW形式のバイナリログ確認には --base64-output=DECODE-ROWS が必要
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
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 | +---------------+-------+
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_FILEとMASTER_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` /*!*/;
--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) |
Linux Master Pro Seminar の詳細を見る >>
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:MySQLのレプリケーションをLinuxサーバー2台で構築する手順|binlogとGTIDによるソース・レプリカ設定
- この記事の属するカテゴリ:データーベース管理へ戻る

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