A copy that follows every change, as files DuckDB reads in seconds.
Minutes behind the source. Not high availability, not a backup. Limits
Zero-ETL analytical replica for MySQL 8.0+, Amazon RDS for MySQL, Aurora MySQL, Percona Server, MariaDB and anything else that writes a MySQL binlog. Your server's binlog goes to DBTrail, and you query the copy with DuckDB. No CDC, no warehouse, no MySQL migration.
Works with
They run in DuckDB, on the copy. Your MySQL never sees them.
only the binlog leaves mysqldIf a few minutes of delay is fine, reports run on the copy. Keep your failover replica.
files, not a serverHow did this row look yesterday? Ask the copy, not MySQL.
as far back as history goesBad UPDATE or DELETE? Get the SQL that puts the rows back.
you read the SQL, you run itThe first two are why you install it. The last two come with the copy.
One Docker Compose stack and a folder or an S3 bucket. The first copy reads your tables. After that, DBTrail folds the binlog into a new Parquet snapshot on the schedule you set.
A generated views.sql gives you state_<schema>_<table> for every table, following the newest snapshot. Your DuckDB runs it: a laptop, a notebook, any machine that can read the files.
Nothing proprietary, and a change history laid out by date and hour. Tables that changed since their last full copy carry small delta files, which the views apply for you in DuckDB. For Spark, Trino or Athena, export a table to Iceberg.
DBTrail connects over the replication protocol, the way a replica does. No plugin, no agent on the database host, no triggers. That is why Amazon RDS and Aurora work.
Both sides of every change, indexed and searchable in the web interface. Deletes surfaced first.
Not the table. Not a restore. DBTrail drafts the SQL that undoes the rows that got hurt. You review it, you run it.
Pick a moment and see the row, or the table, as it stood then: a snapshot plus the changes after it.
Recovery guide →Try time travel in 30 seconds, with nothing of yours connected: docker run --rm -p 6033:6033 ghcr.io/dbtrail/bintrail-demo
Your app never points at the copy. Nothing fails over to it.
History starts the day you install it. Keep your physical backups.
It refreshes on the schedule you set. It needs a ROW binlog with full row images.
Without S3, row history lasts 48 hours. Snapshots stay.
DBTrail and its small index MySQL run on your machines. Disk and backups are yours.
Adding or dropping a column, or a TRUNCATE, makes DBTrail read that table again. That read takes a lock.
Rows a foreign key deletes never reach the binlog. Undo rebuilds them; the copy keeps them until that table is read again.
Reports run in DuckDB, not from your MySQL client. What the MySQL port does
You need Docker with Compose, and DuckDB on the machine where you query.
curl -fsSL …/install.sh | sh starts a Docker Compose stack: DBTrail, its web interface, and a small MySQL that holds the change index.
Open 127.0.0.1:8090 and create a login. Press + Add server and give the host and port of your MySQL. The form shows the SQL that creates DBTrail's user, and bintrail doctor prints the exact fix for any setting it needs.
On Snapshots, press Read database now. Then set a schedule: each update after that folds the recorded changes instead of reading your tables again.
On Snapshots, press Download, then Download the data. Unpack it and, in that folder, run duckdb -init views.sql.
For small tables, occasional queries and no need for history, do that: DuckDB's MySQL extension is free and good at it. It reads your MySQL on every query, though.
| DuckDB ATTACH | DBTrail | |
|---|---|---|
| Where the query runs | Reads your MySQL on every query, competing with your app | Reads the Parquet copy |
| Keeping a copy current | A full read of the table, by hand, each time | Reads the database once, then only the binlog |
| The past | One state: now | Every version of every row since install |
DBTrail captures changes from PostgreSQL 14+ in beta and from MariaDB 10.11+. The Parquet copy that updates on a schedule is built and tested on MySQL; PostgreSQL has no scheduled copy yet.
Not for reports. Report queries run in DuckDB. DBTrail can also open a MySQL port, off by default, that answers one kind of question: what a row or a table looked like at a past moment. It does not run GROUP BY, joins, or filters beyond one column = value.
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.