Library / SDK
blackbeam/rust-mysql-simple avatar
blackbeam/rust-mysql-simple

rust-mysql-simple: a pure Rust MySQL driver that also owns the connection pool

Mysql client library implemented in rust.

693 stars154 forksRustApache-2.0

At a glance

What is it?
rust-mysql-simple is the mysql crate on crates.io, a MySQL driver written in Rust with a connection pool, support for both the text and binary protocols, TLS backends you choose at compile time, and a statement cache per connection. It suits a synchronous Rust service that wants no C dependency in its database layer, and it does not document an async interface.
Who is it for?
Adopt rust-mysql-simple if you are writing a synchronous Rust service against MySQL and want a driver with no C dependency, a built-in pool, and the binary protocol with per-connection statement caching.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 7 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A driver and a pool in one crate

The crate offers a MySQL database driver in pure Rust plus a connection pool. That is the whole product, and the name in the repository, rust-mysql-simple, is a leftover from an earlier naming: the package is published on crates.io as mysql.

The pure Rust part matters more than it sounds. There is no libmysqlclient to install, no FFI boundary and no C toolchain in your build, which is the usual reason a Rust project reaches for a MySQL driver at all. The platform support listed is macOS, Windows and Linux.

The pool is not an add-on. The example in the documentation creates it directly with Pool::new(url) and then takes a connection out of it with pool.get_conn(), so the pool is the entry point rather than something you bolt on later. The URL you hand to the pool is the same URL object that the Opts structure is built from, which keeps the configuration in one place.

The project is not archived, the last push was on 2026-10-16, and the release list shows v28.0.4-2 on 2026-10-16, v28.0.3 on 2026-09-27 and v28.0.2 on 2026-09-01. The Cargo manifest sits at version 28.0.1 with edition 2021, and the crate is dual licensed, with license set to MIT/Apache-2.0 and both LICENSE-MIT and LICENSE-APACHE files in the repository.

Both wire protocols, and the MySQL 8 authentication change

The feature list is where the engineering effort shows, because the driver implements both of the protocols a MySQL server can speak.

The text protocol covers simple text queries and text result sets, and the binary protocol covers prepared statements and binary result sets. Supporting both means the driver can use the binary path where it matters, which is the path that avoids re-encoding values as text on every round trip.

Around that core there is a set of behaviours that only show up in production. There is support for multi-result sets, support for named parameters for prepared statements, and a per-connection cache of prepared statements. The buffer pool is a feature of its own, and there is support for MySQL packets larger than 2^24, Unix sockets and Windows named pipes, custom LOCAL INFILE handlers, and MySql protocol compression.

The authentication plugins are where a MySQL 8 upgrade bites. mysql_native_password covers MySQL prior to version 8, caching_sha2_password is for MySql version 8 and higher, and mysql_clear_password is opt-in through Opts::get_enable_cleartext_plugin.

That last one deserves a pause. Cleartext password authentication sends the password in the clear, so the opt-in exists, and the documentation flags it as opt-in rather than presenting it as a normal option.

Adding the dependency and running a first query

The dependency is added to the dependencies section of your Cargo.toml:

toml
[dependencies]
mysql = "*"

The example program then shows the shape of the API. It takes a connection URL, builds a pool, takes a connection, runs a statement, and maps rows back into a Rust struct.

rust
use mysql::*;
use mysql::prelude::*;

#[derive(Debug, PartialEq, Eq)]
struct Payment {
    customer_id: i32,
    amount: i32,
    account_name: Option<String>,
}

fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
    let url = "mysql://root:password@localhost:3307/db_name";
    let pool = Pool::new(url)?;

    let mut conn = pool.get_conn()?;

Two API details carry most of the weight. The prelude import is what gives you query_drop, exec_batch and query_map, and the params! macro is how the batch insert binds named parameters to the struct fields rather than to a list of positional markers. The result mapping in the example is a closure that destructures a row tuple into the struct, and the documentation notes that MySQL gives no guarantees on the order of returned rows without an ORDER BY, so the example asserts equality only because it assumes it is lucky.

The port in the example URL, 3307, is not arbitrary. It matches the port the project's own test harness starts MySQL on.

Four feature sets, and a TLS choice you make at compile time

The feature layout is unusual and worth understanding before you write the dependency line, because the default set is not minimal and the variants are not just names.

There are four feature sets. default includes buffer-pool, flate2/zlib and derive. default-rust is the same but uses flate2/rust_backend instead of flate2/zlib. minimal includes flate2/zlib only, and minimal-rust includes flate2/rust_backend only. The difference between the two backends is whether the compression support needs a system zlib, which is the practical question when you are building a static binary or a container image.

TLS is four separate features. native-tls specifies native-tls as the TLS backend, rustls-tls specifies rustls using the aws-lc-rs crypto provider, rustls-tls-ring specifies rustls using the ring crypto provider, and rustls selects the backend without a provider. Four ways to say the same thing is a sign that the crypto provider choice has been contested, and the practical advice is to pick the one your organisation has already standardised on.

A set of features is proxied from the companion crate mysql_common, including derive, chrono, time, bigdecimal, rust_decimal, frunk and binlog, and the documentation warns that you have to re-enable the required features when you turn the defaults off:

toml
[dependencies]
# Lets say that we want to use only the `rustls-tls` feature:
mysql = { version = "*", default-features = false, features = ["minimal-rust", "rustls-tls"] }

That line is the one to copy if you care about what ends up in your dependency tree, because default-features = false with an explicit list makes the build reproducible in a way the wildcard version does not.

Connection options come from a URL or from the Opts struct

Opts is the structure that holds the server host name, the client username and password, and the other settings that control client behaviour. You can build it from a URL, and the documentation is specific about the rules: the URL scheme must be mysql, and the host, port and credentials as well as any query parameters have to follow RFC 3986.

The accepted forms are shown like this:

rust
let _ = Opts::from_url("mysql://localhost/some_db")?;
let _ = Opts::from_url("mysql://[::1]/some_db")?;
let _ = Opts::from_url("mysql://user:pass%[email protected]:3307/some_db?")?;

The third one is the interesting case, because a password containing a space has to be percent encoded, and the trailing question mark is legal.

The query parameters map onto the same struct, and the documented list covers user, password, db_name, host, port, pool_min, pool_max, prefer_socket and tcp_keepalive_time_ms. The pool_min and pool_max entries point at the PoolConstraints minimum and maximum, which means the pool size can be set from the connection string rather than only in code.

Two of those deserve a note. prefer_socket ties into the Unix socket and named pipe support, so a client on the same machine as the server can avoid the TCP stack. tcp_keepalive_time_ms is what you tune when a connection sits idle behind a load balancer that drops it.

The test harness starts and secures its own MySQL server

The Makefile in the repository root is a small but complete MySQL test rig, and it is a good indicator of what the driver is exercised against.

It creates a data directory under tests/rust-mysql-simple-test, uses the port 3307, and picks up the SSL material from tests/ca.crt, tests/server.crt and tests/server-key.pem. The server is started with mysqld --initialize-insecure for current versions, and with mysql_install_db for MySQL 5.6 and 5.7 and for MariaDB, so the same rig works across the versions the driver has to support.

The server flags are specific. The bind address is 127.0.0.1, the maximum allowed packet is 32M, innodb_file_per_table is on, the InnoDB log file size is 256M, local-infile is on, and gtid_mode and enforce_gtid_consistency are both enabled, which is the setting that exercises the replication aware paths. The server is started with SSL enabled against the test certificates, and with a unix socket in the data directory, and the script then waits for the port with a loop over nc -z before continuing.

Continuous integration runs through Azure Pipelines, with the badge in the README pointing at the blackbeam Rust project, and the repository also carries a README.tpl that the documentation is generated from, plus a build.rs, since the crate needs a build step.

What the driver does not do, and the choice behind the compression backend

Two limitations are worth stating plainly, one of them a gap in the documentation rather than a missing feature.

The API is synchronous. The pool, the connection handle and the query methods all block, and the documented feature list says nothing about an async interface, so the README does not describe one. A project that has already standardised on an async runtime will find no ready path here, and a project that wants the pure Rust driver without blocking calls has to look elsewhere.

The second is the version churn. The crate sits in the 28.x line, the Cargo manifest declares 28.0.1 while the published tags are already at 28.0.4-2, and a major version bump in a driver that people pin exactly can break a build. The dual licence, MIT/Apache-2.0 with both files present, is the friendly side of that coin.

There is also a real decision inside the crate that mirrors a decision in the wider Rust ecosystem. Choosing flate2/zlib means your build depends on a system zlib, which is the traditional route and the one most CI images already satisfy. Choosing flate2/rust_backend keeps the compression implementation in Rust, at the cost of pulling a different implementation into your tree. The same shape appears in the TLS features, where native-tls leans on the platform and rustls keeps the stack in Rust, and in the choice between the pure Rust driver and a C client reached through FFI, which buys you the same protocol support at the price of a system library and an unsafe boundary.

For a team that wants no C in the build, this crate is the answer. For a team that needs async, it is the wrong answer.

Editorial conclusion

Adopt rust-mysql-simple if you are writing a synchronous Rust service against MySQL and want a driver with no C dependency, a built-in pool, and the binary protocol with per-connection statement caching. Do not adopt it if you need an async database interface, since the documented API and feature list describe a blocking client, or if you want a driver that stays stable across major versions, because the crate is already at 28.x and the version number moves with every release. Verify first which TLS feature you pick, since native-tls, rustls-tls, rustls-tls-ring and rustls compile in different crypto providers, and confirm that your MySQL version matches the authentication plugin you need, with caching_sha2_password for MySQL 8 and higher.

Frequently asked questions

How do I add the mysql crate to a Rust project?

Put mysql = "*" in the dependencies section of your Cargo.toml. The package is published on crates.io as mysql, and the repository is blackbeam/rust-mysql-simple.

Which MySQL authentication plugins does rust-mysql-simple support?

mysql_native_password for MySql prior to version 8, caching_sha2_password for MySql version 8 and higher, and mysql_clear_password which is opt-in through Opts::get_enable_cleartext_plugin.

How do I configure a connection URL for rust-mysql-simple?

The URL scheme must be mysql and the components must follow RFC 3986, and you can pass user, password, db_name, host, port, pool_min, pool_max, prefer_socket and tcp_keepalive_time_ms as query parameters.

What is the difference between the default and default-rust feature sets?

default includes buffer-pool, flate2/zlib and derive, while default-rust is the same but uses flate2/rust_backend instead of flate2/zlib. If you set default-features = false you have to re-enable the features you need, for example features = ["minimal-rust", "rustls-tls"].

Does rust-mysql-simple support TLS and which backends?

TLS is selected at compile time through four features: native-tls, rustls-tls for the aws-lc-rs provider, rustls-tls-ring for the ring provider, and rustls without a provider.

Official sources

  1. blackbeam/rust-mysql-simple on GitHub
  2. Issues
  3. License: Apache-2.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/blackbeam-rust-mysql-simple.svg)](https://hysenlabs.com/projects/blackbeam-rust-mysql-simple)

Was this useful?