free & open source

Time-travel
for your MySQL.

dbtrail remembers every row change — searchable, reversible, yours. The wrong UPDATE becomes a two-minute fix. And it's Apache-2.0 — yours to run anywhere.

$ curl -fsSLO https://raw.githubusercontent.com/dbtrail/dbtrail/main/docker-compose.yml $ docker compose up -d
Apache-2.0 MySQL 8.0+ ~1 min to running zero footprint
Deleted at 14:04.
Back by 14:06.
mysql> SELECT * FROM customers WHERE id = 4827; Empty set (0.00 sec) mysql> -- whoops. what was it at 14:04? mysql> SELECT * FROM _flashback.customers -> AS OF '2026-06-10 14:04:00' WHERE id = 4827; +------+-----------+------+ | 4827 | Acme Corp | gold | +------+-----------+------+ 1 row in set (0.02 sec)

Compatible with

127.0.0.1:8090 — dbtrail console

Overview

What changed recently, and where — your starting point. 1 delete(s) in the latest window: the ones worth a look first.

1229changes indexed
1deletes
15tables touched
2026-06-10 22:50:44most recent change
Recent changes
22:50:44DELETEshop_prod.customers · pk 48274 cols
22:50:21UPDATEshop_prod.customers · pk 48271 col
22:50:34INSERTshop_prod.orders · pk 9114
22:49:31INSERTshop_prod.order_items · pk 22871
22:48:55UPDATEshop_prod.products · pk 10421 col
Activity by table
shop_prod.order_items412
shop_prod.orders307
shop_prod.sessions268
shop_prod.customers141
shop_prod.products89
shop_prod.inventory12

Events

Browse indexed row events with full before / after images.

100 event(s)j/k move · ↵ expand · u undo · JSON · CSV
timetabletypepkchanged
2026-06-10 22:50:44shop_prod.customersDELETE48274 cols
columnbeforeafter
name"Acme Corp"— deleted —
tier"gold"
last_seen2026-06-10 21:58:02
Generates reversal SQL — nothing runs automatically.
2026-06-10 22:50:21shop_prod.customersUPDATE48271 col
2026-06-10 22:50:34shop_prod.ordersINSERT9114
2026-06-10 22:49:31shop_prod.order_itemsINSERT22871

Recover

Filter the changes you want to undo, preview the affected rows, then generate reversal SQL. Nothing is ever executed — copy or download the script and apply it yourself after review.

DELETE RESTORING THIS ROW · DELETED AT THIS POINT
shop_prod.customers · pk 4827
undoing changes up to DELETE at 2026-06-10 22:50:44
Schema
shop_prod
Table
customers
PK
4827
Since
YYYY-MM-DD HH:MM
Until
2026-06-10 22:50:44
reversal.sql · 2 statement(s) from 2 event(s)
-- Generated by bintrail recover at 2026-06-11 12:16:29 UTC -- Events to reverse: 2 -- IMPORTANT: Review carefully before applying to production. BEGIN; -- [1318] restore DELETE on shop_prod.customers pk=4827 at 2026-06-10 22:50:44 INSERT INTO `shop_prod`.`customers` (`id`, `name`, `tier`, `last_seen`) VALUES (4827, 'Acme Corp', 'gold', '2026-06-10 21:58:02'); -- [1317] reverse UPDATE on shop_prod.customers pk=4827 at 2026-06-10 22:50:21 UPDATE `shop_prod`.`customers` SET `tier` = 'gold' WHERE `id` = 4827; COMMIT;

↑ The actual console — it ships in the compose file. Click through the sidebar: Overview, Events with before/after diffs, and Recover with the reversal SQL it drafts. Nothing ever runs without you.

everything it does

A memory for your database.
And an undo button.

time-travel sql

Query any moment, over plain MySQL protocol.

Point your client at the time-travel endpoint and add AS OF. No driver changes, no new query language — your ORM already speaks it.

SELECT * FROM orders AS OF '2026-06-10 14:00:00' WHERE customer_id = 4827; -- 1 row. it's back.
see every change

Before → after, every row.

Full images of both sides of every change, indexed and searchable. Deletes surfaced first.

price: 29.99 + price: 2.99 products · pk 1042 · 22:48:55
undo precisely

Reversal SQL for just the damaged rows.

Not the table. Not a restore. dbtrail drafts the exact SQL to undo the rows that got hurt — you review, you run. Always dry-run first.

UPDATE products SET price=29.99 WHERE id=1042; -- 1 row, dry-run ✓
mcp · ask claude

"What happened to customer 4827?"

what happened to customer 4827? One DELETE at 22:50:44. The full before-image is preserved — want the reversal SQL? yes please 🙏
grows with you

Old history rotates to Parquet — on disk or S3.

Partitions age out of the hot index into Parquet files on local disk or any S3-compatible bucket. Time-travel queries read them transparently. No cloud account required, no history lost.

zero footprint

Nothing on your DB host.

dbtrail connects like a replica would — over the replication protocol. No agents, no triggers, no schema changes, and no locks on your tables. RDS and Aurora work without host access.

quickstart

Up and running before
your coffee cools.

Compose up

curl -fsSLO …/docker-compose.yml then docker compose up -d. The stack ships its own index store.

Create your login

Open 127.0.0.1:8090 — local-only by default. First run asks for a username and password. Done.

Add your MySQL

Host, user, password — REPLICATION SLAVE + REPLICATION CLIENT is all it needs, so RDS/Aurora work without host access. Preflight checks run (bintrail doctor prints exact fixes), then events stream within the minute.

It's yours. Really.

Apache-2.0 — free for any use, commercial and production included. We'd love your issues, ideas, and PRs. The CLA bot says hi on your first one.

github.com/dbtrail/dbtrail · 30-second demo: docker run ghcr.io/dbtrail/bintrail-demo

Don't want to babysit the index store?

Totally fair — it's your forensic record, and its disks and backups deserve care. If you'd rather we do that part, the managed service runs the same code, operated by us. It's also what keeps the lights on here.

peek at dbtrail cloud →