How to Connect to MariaDB from Rust
There is no MariaDB-specific Rust driver, and you do not need one. MariaDB speaks the MySQL wire protocol, so the same crates that connect to MySQL connect to MariaDB: mysql (sync), mysql_async (tokio), and sqlx. If you have read our MySQL from Rust guide, everything there applies here.
This guide covers what actually differs. Two things are genuinely MariaDB-specific from Rust's point of view: the ed25519 and PARSEC authentication plugins -- where crate support varies in ways that produce confusing failures -- and INSERT ... RETURNING.
The options
| Library | Model | MariaDB ed25519 auth | Version (as of July 2026) |
|---|---|---|---|
mysql | Sync driver, pure Rust, pool included | Yes, behind the client_ed25519 feature | 28.0.0 |
mysql_async | Async driver (tokio), pure Rust, pool included | Yes, behind the client_ed25519 feature | 0.37.0 |
sqlx | Async toolkit, compile-time checked SQL | No | 0.9.0 |
| Diesel | Sync ORM, binds to the C client library | Depends on the installed client library | 2.3.11 |
Connecting
The URL scheme is mysql:// regardless of which server is on the other end -- there is no mariadb:// scheme in these crates:
[dependencies]
mysql = "28"use mysql::*;
use mysql::prelude::*;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let url = "mysql://app:secret@localhost:3306/mydb";
let pool = Pool::new(url)?;
let mut conn = pool.get_conn()?;
let version: String = conn.query_first("SELECT VERSION()")?.unwrap();
println!("{version}"); // e.g. 11.8.3-MariaDB
Ok(())
}The async variant is the same shape with mysql_async::Pool and .await. Both dedicated drivers ship a built-in connection pool -- no separate pooling crate needed. Prepared statements use ? positional placeholders; named parameters (:name) are translated client-side by the driver, so a literal :something inside a string in your SQL can be misparsed -- the same quirk as with MySQL.
As with MySQL, use utf8mb4. MariaDB's utf8 is the legacy 3-byte alias (utf8mb3); emoji and supplementary-plane characters need utf8mb4 tables and connections.
Authentication: where MariaDB actually differs
MariaDB does not use caching_sha2_password, MySQL 8's default plugin. Standard MariaDB password accounts use mysql_native_password, which every Rust crate supports out of the box. So the MySQL 8 auth headache is absent -- but MariaDB has two plugins of its own.
ed25519
MariaDB's ed25519 plugin replaces SHA-1 password hashing with an elliptic-curve signature scheme. Accounts created with IDENTIFIED VIA ed25519 fail against clients that don't implement it -- with correct credentials. In several language ecosystems (Ruby, PHP) no driver implements it at all.
Rust is better off: mysql and mysql_async both support it, but only behind a feature flag, because it pulls in extra cryptography dependencies:
[dependencies]
mysql = { version = "28", features = ["client_ed25519"] }
# or
mysql_async = { version = "0.37", features = ["client_ed25519"] }Without the feature, connecting to an ed25519 account fails with an "unknown authentication plugin" error even though the password is right. Enable the feature; don't downgrade the account.
sqlx does not implement ed25519 (its MySQL auth covers mysql_native_password, caching_sha2_password, and sha256_password). If your MariaDB accounts use ed25519, sqlx cannot log in -- switch the account to mysql_native_password or use one of blackbeam's drivers.
PARSEC (MariaDB 11.6+)
MariaDB 11.6 introduced PARSEC (PBKDF2 plus an ed25519 signature), which MariaDB intends to make the default plugin in a future release. Same story: mysql and mysql_async support it behind the client_parsec feature; sqlx does not. If you run MariaDB 11.6+ and a future upgrade flips the default, this feature flag is the difference between a working deployment and an authentication mystery.
INSERT ... RETURNING
Since MariaDB 10.5, INSERT ... RETURNING (and DELETE ... RETURNING) returns rows from the statement -- something MySQL still doesn't have. From Rust this is just a query that returns rows, so use the query API, not the exec API:
let id: Option<u64> = conn.query_first(
"INSERT INTO users (email) VALUES ('a@example.com') RETURNING id",
)?;The portable alternative is last_insert_id(), available on the connection after an exec:
conn.exec_drop("INSERT INTO users (email) VALUES (?)", ("a@example.com",))?;
let id = conn.last_insert_id();RETURNING is the better tool when you insert multiple rows (per-row ids, not just the first) or need non-key columns back. Just remember it ties you to MariaDB -- the same statement fails on MySQL with a syntax error.
sqlx with MariaDB
sqlx officially supports MariaDB through its MySQL driver, and its CI tests against MariaDB versions. Everything from the MySQL guide applies -- MySqlPoolOptions, compile-time checked query! macros, the works:
use sqlx::mysql::MySqlPoolOptions;
let pool = MySqlPoolOptions::new()
.max_connections(10)
.connect("mysql://app:secret@localhost:3306/mydb")
.await?;The two caveats: the auth plugin gap above, and that query!'s compile-time verification runs against whatever server DATABASE_URL points at -- point it at MariaDB, not MySQL, or the macros will happily verify SQL that only works on the other server (in either direction).
TLS
Both blackbeam drivers offer native-tls and rustls feature flags; sqlx selects TLS via feature flags (tls-rustls-ring-webpki, tls-native-tls) and ?ssl-mode= in the URL. Verify the server certificate in production (SslOpts with a CA in mysql/mysql_async, ssl-mode=VERIFY_IDENTITY in sqlx); skipping verification protects against passive snooping only.
Common mistakes
| Mistake | Symptom | Fix |
|---|---|---|
| ed25519 account, feature flag missing | Auth fails with correct credentials, "unknown plugin" | features = ["client_ed25519"] on mysql/mysql_async |
| ed25519 or PARSEC account with sqlx | Login fails, no feature flag can fix it | Use mysql_native_password for that account, or switch driver |
Expecting caching_sha2_password issues | Cargo-culted MySQL 8 workarounds that do nothing | MariaDB standard accounts are mysql_native_password -- plain connections just work |
Legacy utf8 charset | Emoji and 4-byte characters rejected or mangled | utf8mb4 tables and connection charset |
RETURNING in portable code | Syntax error on MySQL | Gate it to MariaDB 10.5+, or use last_insert_id() |
| sqlx macros verified against MySQL | Compile-time pass, runtime failure on MariaDB (or vice versa) | Point DATABASE_URL at the server you deploy on |
Once your Rust service is writing to MariaDB, you still need to look at the data. Mako connects to MariaDB alongside PostgreSQL, MySQL, and the rest, with AI-powered autocomplete for exploring schemas you didn't design. Try it free at mako.ai.
Skip the terminal. Use Mako.
Connect your database, write queries with AI assistance, and import/export data in clicks. Free to start.