Point-in-time recovery restores the last full backup, then replays the binary log up to just before the damage. After the dump of Logical Backups (GTIDs 1-25), the source took an order (26, 27), someone ran DROP TABLE reviews (28), and an order was shipped (29). Find the bad transaction:
mysqlbinlog -P 3317 --read-from-remote-server --base64-output=DECODE-ROWS -v \
binlog.000003 > b3.txt
grep -B5 "DROP TABLE" b3.txt | cut -c 1-90 | expandSET @@SESSION.GTID_NEXT= 'f8b4dc41-b72a-11f1-9c16-a282e0d51493:28'/*!*/; # at 1441 #260923 16:56:47 server id 1 end_log_pos 1573 CRC32 0xb3c1539b Query thread_id=43 exec_t SET TIMESTAMP=1790153807/*!*/; SET @@session.pseudo_thread_id=43/*!*/; DROP TABLE `reviews` /* generated by server */
The dump is already restored on the spare server (Logical Backups), with GTID_PURGED at 1-25. Replay the rest of the log without transaction 28:
mysqlbinlog -P 3317 --read-from-remote-server \
--exclude-gtids='f8b4dc41-b72a-11f1-9c16-a282e0d51493:28' binlog.000003 | mysql -P 3417
echo "exit status: $?"
mysql -P 3417 -t shop -e "SELECT id, status, ordered_at FROM orders WHERE id >= 9;
SELECT COUNT(*) AS reviews FROM reviews;"exit status: 0 +----+---------+---------------------+ | id | status | ordered_at | +----+---------+---------------------+ | 9 | shipped | 2026-09-02 08:45:00 | | 10 | paid | 2026-09-23 09:10:00 | +----+---------+---------------------+ +---------+ | reviews | +---------+ | 7 | +---------+
The new order, the shipment and all seven reviews are back. Transactions 1-25 in the log were skipped silently, because their GTIDs were already executed: GTID replay is idempotent. Without GTIDs, start at the dump's --start-position=762 and end with --stop-position or --stop-datetime. The rescued table went back to the source with mysqldump -P 3417 --set-gtid-purged=OFF shop reviews | mysql -P 3317 shop. Keep binary logs at least as long as the gap between full backups, off the server.