This blog is about how to perform PITR: 8.0 Reference.
What is PITR
PITR(point-in-time-recovery) is a recovery technique that allows you to restore your database to an exact state at a specific moment in time (e.g. “right before I accidentally dropped that table at 2:30 PM yesterday”).
Enabling the binary log is a prerequisite for performing point-in-time recovery in MySQL. Here’s 2 major phases:
- Full Backup (
Baseline
): To perform PITR, you first need a full backup of your database. This backup captures the state of your database at a specific moment. - Binary Log (
Incremental Changes
): After your full backup, any subsequent changes to the database are recorded in the binary log.
The PITR Process
- You restore your database from the most recent full backup.
- You then use the binary log to roll forward the database by replaying all the changes that occurred after that full backup, up to the desired point in time.
- The
mysqlbinlog
utility is typically used to read the binary log files and convert them into SQL statements (or other formats), which are then applied to the restored database.
Goal
Performing a partial table PITR on the same instance to recover the accidentally dropped table and retain the updates on other tables.
Vagrant
The playground is managed by Vagrant, please launch it before move on to the next section.
Data Seed
On server, let’s create an animals DB and table animals
and food
:
1 | CREATE DATABASE IF NOT EXISTS animals; |
Full Instance Backup
Create a new folder for backup hosting:
1 | # Create a folder to host dump |
At this point we take a full instance backup using mysqlsh
:
1 | mysqlsh \ |
The output is like:
1 | WARNING: Using a password on the command line interface can be insecure. |
The dump file functions in terms of table animals.animals
:
1 | animals@animals@@0.tsv.zst <- compressed table data (actual rows) |
You can view the plain row data with zstd
decoding:
1 | zstd -d < animals@animals@@0.tsv.zst |
Drop Table
Now drop the table animals
, then we do insert on table food
after table
animals
is dropped:
1 | INSERT INTO animals.animals (name, species, age) VALUES |
Partial Table PITR
Now, we want to bring table animals
back and keep the changes on table food
.
First, back up the bin log files:
1 | # You can use SHOW VARIABLES LIKE 'log_bin%'; to check binlog path |
Replay Full Backup
The current master status:
1 | mysql> show master status\G |
Run dump load with mysqlsh
for animals
table only:
1 | # You must specify includeTables, otherwise you will have conflicts errors |
Now we can see animals.animals
table is back at the time of full instance
backup, but the last insert is missing because it is after the full instance
backup:
1 | mysql> SELECT * FROM animals.animals; |
Now check the master status, the Position
is updated from 2374
to 3469
:
1 | mysql> show master status\G |
Inspect Binlog
We then need to check bin log to find the exact moment when the animals.animals
was dropped and we will replay the SQL before it to bring the missing insert row
back.
First go to find the binlog coordinates, it is in @.json
file (on show the
irrelevant lines):
1 | { |
Then we inspect the binlog.000002
and its successors(if they are) to find the
time window between the missing insert and drop of animals.animals
table.
Please note here is just a simple case, as we don’t have SQLs from other tables, otherwise you need some manual work to filter them out.
1 | sudo mysqlbinlog \ |
1 | # 250705 20:41:42 server id 1 end_log_pos 1817 CRC32 0xb27353c1 Write_rows: table id 125 flags: STMT_END_F |
1 | sudo mysqlbinlog \ |
1 | # 250705 20:41:46 server id 1 end_log_pos 2066 CRC32 0x2d60fed1 Query thread_id=8 exec_time=0 error_code=0 Xid = 101 |
Replay Binlog
Now we can replay the missing insert for table animals.animals
:
1 | # --start-datetime 2025-07-05 20:41:42, inclusive for insert SQL |
Verification
Now, checking and we can see the missing insert is back:
1 | mysql> SELECT * FROM animals.animals; |