How to Connect to MariaDB from Ruby
There is no MariaDB-specific Ruby driver, and you do not need one. MariaDB speaks the MySQL wire protocol, so the same Ruby drivers that connect to MySQL connect to MariaDB: mysql2 and trilogy. This guide shows both, plus Sequel and ActiveRecord on top, and focuses on the two things that actually differ between MariaDB and MySQL from Ruby's point of view: the ed25519 authentication plugin, and INSERT ... RETURNING.
The options
| Library | Native dependency | Notes | Version (as of July 2026) |
|---|---|---|---|
mysql2 | libmysqlclient / libmariadb | Mature, widely deployed default | 0.5.7 |
trilogy | None (pure protocol implementation) | No client lib to build; Rails-native adapter | 2.12.6 |
| Sequel | via mysql2 or trilogy | Toolkit/ORM, uses a driver underneath | 5.106.0 |
| ActiveRecord | via mysql2 or trilogy | Full ORM (Rails) | ships with Rails 8.1.3 |
The practical decision is the same as for MySQL:
mysql2if you want the established option and don't mind installing client libraries at build time. Installing the MariaDB client library (libmariadb-dev) satisfies its dependency perfectly well.trilogyif you want to avoid the C client build dependency (a frequent source of CI and Docker friction) or you are on a recent Rails and want the natively supported adapter.
Installing mysql2 against MariaDB
The gem compiles against a MySQL-compatible client library. The MariaDB Connector/C works and is often the cleaner install on modern systems:
- Debian/Ubuntu:
sudo apt-get install libmariadb-dev - macOS (Homebrew):
brew install mariadb-connector-c - RHEL/Fedora:
sudo dnf install MariaDB-shared MariaDB-devel
gem install mysql2If the build cannot find the client headers, the dev package is missing. trilogy skips this entirely because it implements the protocol in Ruby with no C client to link against.
A minimal connection with mysql2
require 'mysql2'
client = Mysql2::Client.new(
host: 'localhost',
port: 3306,
username: 'app',
password: ENV['DB_PASSWORD'],
database: 'shop',
encoding: 'utf8mb4'
)
client.query('SELECT VERSION()').each do |row|
puts row['VERSION()'] # e.g. "11.4.2-MariaDB"
end
client.closeThe utf8mb4 trap
This applies to MariaDB exactly as it does to MySQL. In this ecosystem utf8 is a historical alias for a 3-byte encoding that cannot store 4-byte characters (emoji, some CJK characters, many symbols). Set utf8mb4 everywhere: in the driver connection (encoding: 'utf8mb4'), and on the database, tables, and columns. Mismatched charsets produce Incorrect string value errors on insert, or silent data loss on older configurations. Use utf8mb4 end to end and the problem disappears.
The ed25519 authentication gotcha (this is the MariaDB-specific one)
Here is the genuine MariaDB difference. MariaDB does not use MySQL 8's caching_sha2_password plugin, so the whole "Authentication plugin caching_sha2_password cannot be loaded" / Public Key Retrieval headache from MySQL 8 simply does not exist here. Good news.
The flip side: MariaDB has its own modern authentication plugin, ed25519, which many MariaDB deployments now use for accounts instead of the legacy mysql_native_password. And the Ruby drivers do not implement the client side of ed25519. If your account was created with:
CREATE USER 'app'@'%' IDENTIFIED VIA ed25519 USING PASSWORD('secret');then a mysql2 or trilogy connection will fail with a "plugin ... could not be loaded" or authentication error, because the driver cannot answer the ed25519 challenge. This is the failure mode that surprises people moving from MySQL: the driver is fine, the credentials are correct, but the auth plugin is one Ruby's clients don't speak.
Your options:
- Use a
mysql_native_passwordaccount for the Ruby app. Create or alter the service account to use native password auth:ALTER USER 'app'@'%' IDENTIFIED VIA mysql_native_password USING PASSWORD('secret');. This is the pragmatic path today. - Build
mysql2against a MariaDB Connector/C that has the ed25519 client plugin available, and ensure the plugin.sois discoverable. This works with the C client but adds deployment complexity, andtrilogy(pure Ruby) still cannot do it.
If a MariaDB connection that has correct credentials keeps failing, check the account's plugin with SELECT user, plugin FROM mysql.user WHERE user='app'; before assuming a network or password problem.
Parameterized queries and prepared statements
Use bound parameters rather than interpolating into SQL:
stmt = client.prepare('SELECT name, plan FROM accounts WHERE region = ? AND active = ?')
result = stmt.execute('EMEA', true)
result.each { |row| puts "#{row['name']}: #{row['plan']}" }mysql2 uses ? positional placeholders in prepared statements.
INSERT ... RETURNING (a real MariaDB advantage)
MariaDB supports INSERT ... RETURNING (since 10.5), which MySQL does not. Instead of inserting and then reading last_id, you can get generated values back in one round trip:
row = client.query(
"INSERT INTO accounts (name, region) VALUES ('Acme', 'EMEA') RETURNING id, created_at"
).first
puts row['id']
puts row['created_at']This is portable across MariaDB but not to MySQL, so if the same code must run against both, fall back to client.last_id after the insert instead.
Connection pooling
Neither mysql2 nor trilogy pools connections on its own. A Mysql2::Client is a single connection and is not thread-safe for concurrent queries. In a threaded server, use the connection_pool gem:
require 'connection_pool'
require 'mysql2'
POOL = ConnectionPool.new(size: 5, timeout: 5) do
Mysql2::Client.new(
host: 'localhost', username: 'app',
password: ENV['DB_PASSWORD'], database: 'shop',
encoding: 'utf8mb4'
)
end
POOL.with do |client|
client.query('SELECT count(*) AS n FROM accounts').first['n']
endSize the pool so that pool_size × process_count stays under the server's max_connections (151 by default on MariaDB). For heavy connection churn, a proxy like MaxScale or ProxySQL in front of MariaDB does real connection pooling server-side.
Sequel and ActiveRecord
Sequel picks the driver from the URL scheme:
require 'sequel'
# mysql2 driver against MariaDB
DB = Sequel.connect('mysql2://app:secret@localhost/shop?encoding=utf8mb4', max_connections: 5)
# or trilogy
# DB = Sequel.connect('trilogy://app:secret@localhost/shop')
DB[:customers].where(region: 'EMEA').each { |row| puts row[:name] }In Rails, config/database.yml selects the adapter. There is no separate MariaDB adapter; use mysql2 or trilogy:
production:
adapter: mysql2 # or: trilogy
host: <%= ENV['DB_HOST'] %>
database: shop
username: app
password: <%= ENV['DB_PASSWORD'] %>
encoding: utf8mb4
pool: 5TLS connections
To require an encrypted connection and verify the server certificate:
client = Mysql2::Client.new(
host: 'db.internal', username: 'app', password: ENV['DB_PASSWORD'],
database: 'shop', encoding: 'utf8mb4',
sslca: '/etc/ssl/certs/ca.pem',
sslverify: true
)Setting sslca with verification is the meaningful step; enabling TLS without verifying the certificate protects against passive sniffing but not an active man-in-the-middle.
Common errors
| Error | Cause |
|---|---|
| Cannot find client headers at install | MariaDB/MySQL client dev package missing (mysql2 only; trilogy avoids this) |
Can't connect to MySQL server | Wrong host/port, or server not listening on TCP |
Access denied for user | Wrong credentials, or host-pattern account mismatch |
| Auth plugin could not be loaded / auth fails with correct password | Account uses MariaDB ed25519, which the Ruby drivers can't answer; switch the account to mysql_native_password |
Incorrect string value | 4-byte character into a utf8 (3-byte) column; use utf8mb4 end to end |
Too many connections | Pool size × process count exceeds max_connections (151 default) |
Querying without writing connection code
If your goal is to explore a MariaDB database rather than build a service, a GUI client skips all of the above. Mako connects to MariaDB with AI-assisted SQL -- see our MariaDB GUI client guide. Connecting from another language? See How to Connect to MariaDB from Python and from Node.js.
Mako connects to MariaDB with AI-powered autocomplete. 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.