<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/replicating-from-innodb-into-a-duckdb-storage-engine-pye2iwehn" -->

---
title: Replicating from InnoDB into a DuckDB storage engine
description: Percona tested feeding an InnoDB MySQL primary's row-based replication into a replica where tables use the experimental DuckDB storage engine, aiming to get an...
canonical: https://daily.dev/posts/replicating-from-innodb-into-a-duckdb-storage-engine-pye2iwehn
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Replicating from InnoDB into a DuckDB storage engine | daily.dev
og:description: Percona tested feeding an InnoDB MySQL primary's row-based replication into a replica where tables use the experimental DuckDB storage engine, aiming to get an...
og:url: https://daily.dev/posts/replicating-from-innodb-into-a-duckdb-storage-engine-pye2iwehn
og:image: https://api.daily.dev/og/posts/PYe2IwehN.png
og:image:alt: Replicating from InnoDB into a DuckDB storage engine
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Replicating from InnoDB into a DuckDB storage engine

**[Planet MySQL](https://daily.dev/sources/planet-mysql)** · 7 min read · 1 upvotes · 0 comments

## Summary

Percona tested feeding an InnoDB MySQL primary's row-based replication into a replica where tables use the experimental DuckDB storage engine, aiming to get an analytics-ready column store that stays in sync automatically. The first run silently lost data: because replicas write their own position into InnoDB system tables alongside DuckDB data, every applied transaction spans two engines and triggers a two-phase commit, and a bug in the engine's prepare/commit logic dropped the DuckDB writes while reporting success. The fix landed in v0.2.3, after which INSERTs, UPDATEs, DELETEs, all column types, DDL, transactions, bulk loads, graceful restarts, and SIGKILL crash recovery all replicate correctly and match the primary byte-for-byte. The project remains an experiment, not production software, and is available under GPLv2 on GitHub.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://www.percona.com/blog/replicating-from-innodb-into-a-duckdb-storage-engine>

## Questions this post answers

### Why did my DuckDB MySQL replica silently lose data during replication testing?

Because every replicated transaction touches two storage engines at once: InnoDB for the replication position (mysql.slave_worker_info, GTID) and DuckDB for the actual row data, forcing MySQL into a two-phase commit. The engine's prepare step incorrectly moved the open DuckDB transaction into an external XA registry and cleared per-connection state, so commit found nothing to finish and silently discarded the DuckDB writes while the replica reported success.

_Track fixes like this two-phase-commit bug on daily.dev before wiring MySQL replication into a DuckDB analytics replica._

### Can I replicate an InnoDB MySQL primary into a DuckDB storage engine replica for analytics?

Yes, on version 0.2.3 of the experimental Percona-Lab ducksdb-mysql-engine project, an InnoDB primary can feed a DuckDB replica through normal row-based MySQL replication. Inserts, updates, deletes, all common column types, DDL changes, transactions, bulk LOAD DATA, graceful restarts, and SIGKILL crash recovery all replicate correctly and match byte-for-byte, though it remains an experiment untested for multi-source replication or high write rates.

_Compare experimental storage-engine setups like this DuckDB replica approach on daily.dev before adopting one for reporting._

### How do you set up a DuckDB replica table for MySQL replication without it becoming InnoDB?

You must manually pre-create the replica tables with ENGINE=DuckDB before replication starts, because a CREATE TABLE statement logged from an InnoDB primary carries the ENGINE=InnoDB clause into the binlog and the replica applies it exactly as written, producing an InnoDB table instead. A primary key is also required on the replica table so UPDATE and DELETE row events can locate rows by their old image.

_Check setup gotchas like this DuckDB replica table requirement on daily.dev before running your own replication spike._

## Similar posts on daily.dev

- [DuckDB Speed on MySQL with dbtrail, Without a New Storage Engine](https://daily.dev/posts/duckdb-speed-on-mysql-with-dbtrail-without-a-new-storage-engine-0gt0zkgml) · Planet MySQL · 1 upvotes · 0 comments
- [Running DuckDB as a MySQL 9.7 storage engine](https://daily.dev/posts/running-duckdb-as-a-mysql-9-7-storage-engine-hhxnvb0s1) · Percona Blog · 0 upvotes · 0 comments
- [Trying DuckDB for Magento Analytics: An Experiment with One Million Orders](https://daily.dev/posts/trying-duckdb-for-magento-analytics-an-experiment-with-one-million-orders-xunzodi5k) · MariaDB.org · 0 upvotes · 0 comments
- [The DuckDB MySQL engine at 500 GB](https://daily.dev/posts/the-duckdb-mysql-engine-at-500-gb-baqjll9pk) · Planet MySQL · 0 upvotes · 0 comments

---

Tags: [#mysql](https://daily.dev/tags/mysql), [#duckdb](https://daily.dev/tags/duckdb)

[View this post on daily.dev](https://daily.dev/posts/replicating-from-innodb-into-a-duckdb-storage-engine-pye2iwehn)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Replicating from InnoDB into a DuckDB storage engine","url":"https://daily.dev/posts/replicating-from-innodb-into-a-duckdb-storage-engine-pye2iwehn","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/replicating-from-innodb-into-a-duckdb-storage-engine-pye2iwehn"},"datePublished":"2026-08-13T17:36:54.091Z","dateModified":"2026-09-13T19:44:41.812Z","description":"Percona tested feeding an InnoDB MySQL primary's row-based replication into a replica where tables use the experimental DuckDB storage engine, aiming to get an...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/31ecae6c14430c8300903342afde2a30?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/31ecae6c14430c8300903342afde2a30?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Planet MySQL","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Planet MySQL","logo":"https://media.daily.dev/image/upload/s--UKAtmXTq--/f_auto,q_auto/v1780213421/logos/planet-mysql?_a=BAMAMiWQ0","url":"https://daily.dev/sources/planet-mysql"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/replicating-from-innodb-into-a-duckdb-storage-engine-pye2iwehn","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":1},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"mysql,duckdb","timeRequired":"PT7M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Planet MySQL","item":"https://daily.dev/sources/planet-mysql"},{"@type":"ListItem","position":3,"name":"Replicating from InnoDB into a DuckDB storage engine"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/replicating-from-innodb-into-a-duckdb-storage-engine-pye2iwehn#faq","mainEntity":[{"@type":"Question","name":"Why did my DuckDB MySQL replica silently lose data during replication testing?","acceptedAnswer":{"@type":"Answer","text":"Because every replicated transaction touches two storage engines at once: InnoDB for the replication position (mysql.slave_worker_info, GTID) and DuckDB for the actual row data, forcing MySQL into a two-phase commit. The engine's prepare step incorrectly moved the open DuckDB transaction into an external XA registry and cleared per-connection state, so commit found nothing to finish and silently discarded the DuckDB writes while the replica reported success. Track fixes like this two-phase-commit bug on daily.dev before wiring MySQL replication into a DuckDB analytics replica."}},{"@type":"Question","name":"Can I replicate an InnoDB MySQL primary into a DuckDB storage engine replica for analytics?","acceptedAnswer":{"@type":"Answer","text":"Yes, on version 0.2.3 of the experimental Percona-Lab ducksdb-mysql-engine project, an InnoDB primary can feed a DuckDB replica through normal row-based MySQL replication. Inserts, updates, deletes, all common column types, DDL changes, transactions, bulk LOAD DATA, graceful restarts, and SIGKILL crash recovery all replicate correctly and match byte-for-byte, though it remains an experiment untested for multi-source replication or high write rates. Compare experimental storage-engine setups like this DuckDB replica approach on daily.dev before adopting one for reporting."}},{"@type":"Question","name":"How do you set up a DuckDB replica table for MySQL replication without it becoming InnoDB?","acceptedAnswer":{"@type":"Answer","text":"You must manually pre-create the replica tables with ENGINE=DuckDB before replication starts, because a CREATE TABLE statement logged from an InnoDB primary carries the ENGINE=InnoDB clause into the binlog and the replica applies it exactly as written, producing an InnoDB table instead. A primary key is also required on the replica table so UPDATE and DELETE row events can locate rows by their old image. Check setup gotchas like this DuckDB replica table requirement on daily.dev before running your own replication spike."}}]}
```

