Reads the binlog like a replica

Analytics on your MySQL,
without slowing it down.

A copy that follows every change, as files DuckDB reads in seconds.

$ curl -fsSL https://raw.githubusercontent.com/dbtrail/dbtrail/main/install.sh | sh

Minutes behind the source. Not high availability, not a backup. Limits

Apache-2.0

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

what you do with it

Four things you do
with the copy.

reports MYSQLD · APP InnoDB BUFFER POOL · LOCKS your transactions DuckDB 3 joins · GROUP BY over the copy own process OUTSIDE MYSQLD

Heavy queries, not on your MySQL

They run in DuckDB, on the copy. Your MySQL never sees them.

only the binlog leaves mysqld
replica READ REPLICA MYSQLD · AGAIN InnoDB patch · upgrade a second server to run DISK OR BUCKET orders.parquet customers.parquet plain Parquet NO SERVER

Drop the reporting replica

If a few minutes of delay is fine, reports run on the copy. Keep your failover replica.

files, not a server
look back yesterday now account 42 plan: pro account 42 plan: free A ROW OR A TABLE, AS IT WAS

See old data

How did this row look yesterday? Ask the copy, not MySQL.

as far back as history goes
undo 14:03 good 14:04 UPDATE, no WHERE undo SQL copy CHECKED · NO RESTORE

Undo mistakes

Bad UPDATE or DELETE? Get the SQL that puts the rows back.

you read the SQL, you run it

The first two are why you install it. The last two come with the copy.

the analytical copy

Your MySQL, as Parquet,
on disk or in S3.

zero-etl

Zero-ETL, and no warehouse to run.

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.

duckdb, ready to open

One file, one view per table.

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.

open files

Plain Parquet other engines read.

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.

nothing inside the server

Nothing installed in MySQL.

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.

from the same stream

Every version of every row.
And the SQL to undo one.

see every change

Before and after, every row.

Both sides of every change, indexed and searchable in the web interface. 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 SQL that undoes the rows that got hurt. You review it, you run it.

UPDATE products SET price=29.99 WHERE id=1042;
time travel

A row or a whole table, as it was.

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

limits

A copy you can trust
is one whose edges you know.

availability your app MySQL primary READS AND WRITES the copy NO FAILOVER

Not high availability

Your app never points at the copy. Nothing fails over to it.

backup nothing history INSTALL DAY xtrabackup KEEP YOURS

Not your backup

History starts the day you install it. Keep your physical backups.

lag your schedule REQUIRED binlog ROW FULL images

Minutes behind, not seconds

It refreshes on the schedule you set. It needs a ROW binlog with full row images.

history LOCAL DISK ONLY 48 h WITH AN S3 BUCKET as long as you keep it SNAPSHOTS STAY

History needs a bucket

Without S3, row history lasts 48 hours. Snapshots stay.

operations you run these DBTrail indexa small MySQL disk ON YOUR MACHINES

Yours to operate

DBTrail and its small index MySQL run on your machines. Disk and backups are yours.

full copy ADD COLUMN orders read again a lock EVERYDAY CHANGES: NO LOCKS

Some changes mean a full copy

Adding or dropping a column, or a TRUNCATE, makes DBTrail read that table again. That read takes a lock.

cascades customer 7 IN BINLOG order 101 order 102 NOT IN BINLOG MYSQL BEFORE 9.6

Cascaded deletes before MySQL 9.6

Rows a foreign key deletes never reach the binlog. Undo rebuilds them; the copy keeps them until that table is read again.

protocol mysql client DuckDB the copy REPORTS RUN IN DUCKDB

Not a MySQL server

Reports run in DuckDB, not from your MySQL client. What the MySQL port does

quickstart

From install to your first query.

You need Docker with Compose, and DuckDB on the machine where you query.

One command

curl -fsSL …/install.sh | sh starts a Docker Compose stack: DBTrail, its web interface, and a small MySQL that holds the change index.

Sign in and connect

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.

First copy

On Snapshots, press Read database now. Then set a schedule: each update after that folds the recorded changes instead of reading your tables again.

Query it

On Snapshots, press Download, then Download the data. Unpack it and, in that folder, run duckdb -init views.sql.

questions

Asked before you ask.

Why not just ATTACH my MySQL in DuckDB?

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 ATTACHDBTrail
Where the query runsReads your MySQL on every query, competing with your appReads the Parquet copy
Keeping a copy currentA full read of the table, by hand, each timeReads the database once, then only the binlog
The pastOne state: nowEvery version of every row since install
What about PostgreSQL and MariaDB?

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.

Can I query it from my MySQL client?

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.

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