ElyraSQL 1.0 — A Database That Refuses to Lose to History
ElyraSQL 1.0 is here — the first stable release of a single-file, MySQL-compatible database written in Rust. A correctness-and-robustness release with real bug fixes, streaming joins, and a fair benchmark where a row store beats PostgreSQL 17 and MySQL 8.4 on every aggregation query. Plus a note on benchmarking honestly.
There's a particular kind of quiet that settles in when a version number finally drops its leading zero. For months, ElyraSQL lived in the land of 0.x — that comfortable, forgiving place where "not yet" is always a valid answer. Today it steps out of it. ElyraSQL 1.0 is here, and it's our first stable release.
I want to tell you about it the way you'd tell a friend over coffee — not with a spec sheet, but with the story of what it actually took.
The premise that started it all
The idea was almost stubborn: build a SQL server, in Rust, that speaks MySQL's wire protocol so fluently that your existing tools never know the difference — and make it fast. Not "fast for a new database," but genuinely, honestly faster than the twenty- and thirty-year-old engines that run the world. A 2026 database, we decided, has no business losing to software older than most of the people using it.
Five pillars held it up from the beginning: a robust server-side SQL engine written in Rust, MySQL wire compatibility, everything in a single ACID file, native vector search, and an OLAP-ready query path. Everything since has been in service of those.
What 1.0 actually means
A 1.0 isn't about adding the most features. It's about being able to look someone in the eye and say this behaves the way you expect. So this release is, more than anything, a correctness and robustness release.
We found and fixed real bugs — the honest, uncomfortable kind:
SELECT DISTINCTwasn't actually deduplicating on one of its paths. It quietly returned duplicate rows. That's the sort of bug that erodes trust, and it's fixed now, collation-aware, beforeLIMITas MySQL demands.Native prepared statements would desync when a client like PDO pipelined its commands. We root-caused it to a use-after-free in our wire packet reader — not a cosmetic encoding issue, a genuine memory-lifetime bug — and fixed it. PDO with
EMULATE_PREPARES=falsenow just works.A fuzzer we built found a UTF-8 slicing panic the very first time it ran in CI, in code four thousand property-test cases had already walked past. That's the whole point of fuzzing, and it earned its keep on day one.
Alongside the fixes, the SQL surface grew up: first-class BIGINT UNSIGNED with exact 64-bit arithmetic and every bitwise operator (yes, including unary ~ with the correct unsigned semantics), GROUP BY ... WITH ROLLUP, per-column BINARY collation honored everywhere — order by, group by, distinct, join keys — ENUM/SET validation, and qualified wildcards. Small things, individually. Together, they're the difference between "compatible" and compatible.
The part I'm quietly proud of
We taught ElyraSQL to stream large joins. When you join a fact table to its dimensions and then aggregate or sort, ElyraSQL no longer materializes the whole join in memory — it streams the driving table through a spilling aggregator, bounded by the size of your result, not your input. INNER and LEFT joins, explicit or comma-style, two tables or a chain of them.
And here's where the stubborn premise pays off. On a fair, native-Linux benchmark — same host, same client, MySQL 8.4 and PostgreSQL 17 as the competition — ElyraSQL is the fastest of the three on every aggregation query on a million rows:
Query ElyraSQL PostgreSQL 17 MySQL 8.4
----------------------- --------- -------------- ---------
Global aggregation 35.9 ms 45.1 ms 162.4 ms
GROUP BY (100 groups) 48.5 ms 75.0 ms 312.2 ms
GROUP BY + top-10 53.5 ms 95.9 ms 344.6 ms
Filtered aggregation 50.5 ms 54.5 ms 229.5 msTwo to six times ahead of MySQL. Up to nearly twice PostgreSQL on the hard, high-cardinality grouping. That's unusual for a row store, and it comes from real work: parallel clustered scans, vectorized columnar aggregation over flat arrays, a compiled filter predicate. On a plain COUNT(*) the three engines land within noise of each other — and I'll tell you that honestly rather than round it up into a headline.
On honesty
That last sentence matters to me more than the fast ones. There's a temptation, at 1.0, to sand off every rough edge in the marketing. We didn't. The limitations page is a plain inventory of what ElyraSQL doesn't do yet — RIGHT/FULL/non-equi joins still materialize rather than stream (correct, just not memory-bounded on the rare giant join), a few smaller unsigned integer types still map to signed. A database asks for your trust with your data. It should earn it by telling you the truth.
The bit about where it comes from
ElyraSQL is part of the Elyra family, and it was built — line by line, bug by bug, benchmark by benchmark — with a genuine fondness for the craft. There's a whole test net underneath it now: end-to-end wire tests driven by an independent MySQL client, crash-recovery durability tests that SIGKILL the server mid-commit and check the rows survived, a Laravel/Eloquent compatibility suite in CI, property tests, and a cargo-fuzz target guarding the parser. All of it green on every commit.
If you want to try it, a single static binary and a single .edb file is the whole story:
docker run -p 3307:3307 -v elyra:/var/lib/elyrasql ghcr.io/kwhorne/elyrasql:1.0.0
Point your MySQL client at it. SELECT VERSION(); will wink back at you.
Thank you for reading, and thank you to everyone who kicked the tires while the zero was still out front. Here's to 1.0 — and to a database that simply refuses to lose to history.
Made with ❤️ from Norway 🇳🇴