MariaDB
Tested with: MariaDB 11.8 on Databasezy · zb CLI 0.1
MariaDB is the community-developed fork of MySQL. It speaks the MySQL wire protocol, so MySQL drivers, ORMs and tools connect unchanged, and it adds its own features on top.
Overview
Section titled “Overview”Each instance is a MariaDB server managed by
mariadb-operator, using the official MariaDB server image.
It starts with one database and one user, both called app. The root account stays inside the cell and is never
handed out. On paid plans you can add replicas for high availability (--ha, --replicas): asynchronous replication
with automatic failover, writes on the primary and a read-only host on the replicas. TLS is required at the gateway, and the hop from the gateway to the server is encrypted again with the
cell’s internal certificate authority.
| Status | Available |
|---|---|
| Category | Relational |
| Versions | 11.8, 11.4, 10.11 (newest is the default) |
| Protocol and port | MySQL wire protocol on 3306 |
| Runtime | Operator-backed (mariadb-operator) |
| Backups | mysqldump (logical dump) |
| Point-in-time recovery | No |
| Pause | Scale to zero |
| Free plan | Yes (size f0) |
| Features | Read replicas, High availability (standby) |
| Licence | GPL-2.0 |
When to use it
Section titled “When to use it”- You already run MariaDB, or an application that is tested against it (many WordPress, Drupal and PHP stacks).
- You want MariaDB-specific features such as system-versioned (temporal) tables, sequences or the
RETURNINGclause. - You want a MySQL-compatible database on the Free plan.
Pick MySQL instead when your application depends on MySQL 8.x behaviour that MariaDB does not share,
such as MySQL’s binary JSON type or the utf8mb4_0900_* collations, or when you want continuous sync during a
migration, which MariaDB migrations do not offer yet.
Create an instance
Section titled “Create an instance”- Open the portal and choose New instance.
- Pick MariaDB and a version (11.8, 11.4, 10.11).
- Choose a size and region. On the Free plan the size is f0. Secure placement is listed only after your organization has signed the BAA.
- Check the hourly price and monthly estimate, then confirm. The Connect tab fills in when the instance is ready.
zb instances create --engine mariadb --engine-version 11.8 \ --size s1 --region us-east --name mariadb-demo --wait# On the Free plan, use --size f0
# Reveal the credentials once and store them in your secret managerzb instances credentials reveal mariadb-democurl -sS https://api.databasezy.com/v1/orgs/$ZB_ORG/projects/$ZB_PROJECT/instances \ -H "Authorization: Bearer $ZB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "engine": "mariadb", "engine_version": "11.8", "size": "s1", "region": "us-east", "name": "mariadb-demo"}'
The response is 201 with the instance in status requested, or 202 when a
team approval policy applies. See the REST API reference.
Connect
Section titled “Connect”Endpoint and credentials
Section titled “Endpoint and credentials”| Host | mariadb-<id>.<region>.databasezy.com, for example mariadb-7f3k.us-east.databasezy.com |
|---|---|
Port 3306 | MySQL wire protocol |
| TLS | Required on every port; plaintext is refused. Verify the server: ssl-mode=VERIFY_IDENTITY (or --ssl-verify-server-cert) with the CA bundle. |
| Credentials | Username app and a generated password, presented as MySQL/MariaDB password authentication. Shown once at creation; reveal or rotate it from the Connect tab. |
MariaDB uses the MySQL protocol, which negotiates TLS after the server greeting. Always ask the client to verify the
server: ssl-mode=VERIFY_IDENTITY for MySQL drivers, --ssl-verify-server-cert for the mariadb client. A client
that does not request TLS is disconnected.
Drivers and clients
Section titled “Drivers and clients”MariaDB listens on port 3306 (MySQL wire protocol). Versions: 11.8, 11.4, 10.11. Replace the example host with the one on your instance's Connect tab; credentials are shown once at creation.
mysql://app:<password>@mariadb-7f3k.us-east.databasezy.com:3306/app?ssl-mode=VERIFY_IDENTITY&ssl-ca=databasezy-ca.pemimport { readFileSync } from "node:fs";import mysql from "mysql2/promise";
export const pool = mysql.createPool({ host: "mariadb-7f3k.us-east.databasezy.com", port: 3306, user: "app", password: process.env.ZB_PASSWORD, database: "app", ssl: { ca: readFileSync("databasezy-ca.pem", "utf8"), rejectUnauthorized: true, // verify chain and hostname }, connectionLimit: 10,});
const [rows] = await pool.query("select version() as v");console.log(rows[0].v);Tested with: MariaDB 11.8 · mysql2 3.11
import osimport pymysql
conn = pymysql.connect( host="mariadb-7f3k.us-east.databasezy.com", port=3306, user="app", password=os.environ["ZB_PASSWORD"], database="app", ssl={"ca": "databasezy-ca.pem"}, ssl_verify_cert=True, ssl_verify_identity=True, # hostname check)with conn.cursor() as cur: cur.execute("select version()") print(cur.fetchone())Tested with: MariaDB 11.8 · PyMySQL 1.1
package main
import ( "crypto/tls" "crypto/x509" "database/sql" "fmt" "os"
"github.com/go-sql-driver/mysql")
func main() { pem, err := os.ReadFile("databasezy-ca.pem") if err != nil { panic(err) } roots := x509.NewCertPool() roots.AppendCertsFromPEM(pem) mysql.RegisterTLSConfig("databasezy", &tls.Config{ RootCAs: roots, ServerName: "mariadb-7f3k.us-east.databasezy.com", // hostname verification MinVersion: tls.VersionTLS12, })
dsn := fmt.Sprintf("app:%s@tcp(mariadb-7f3k.us-east.databasezy.com:3306)/app?tls=databasezy&parseTime=true", os.Getenv("ZB_PASSWORD")) db, err := sql.Open("mysql", dsn) if err != nil { panic(err) } db.SetMaxOpenConns(10) var v string if err := db.QueryRow("select version()").Scan(&v); err != nil { panic(err) } fmt.Println(v)}Tested with: MariaDB 11.8 · go-sql-driver/mysql 1.8
use sqlx::mysql::{MySqlConnectOptions, MySqlPoolOptions, MySqlSslMode};
#[tokio::main]async fn main() -> Result<(), sqlx::Error> { let opts = MySqlConnectOptions::new() .host("mariadb-7f3k.us-east.databasezy.com") .port(3306) .database("app") .username("app") .password(&std::env::var("ZB_PASSWORD").expect("ZB_PASSWORD")) .ssl_mode(MySqlSslMode::VerifyIdentity) .ssl_ca("databasezy-ca.pem");
let pool = MySqlPoolOptions::new().max_connections(10).connect_with(opts).await?; let (v,): (String,) = sqlx::query_as("select version()").fetch_one(&pool).await?; println!("{v}"); Ok(())}Tested with: MariaDB 11.8 · sqlx 0.8 (mysql, tls-rustls)
// One-time: import the CA into a PKCS12 truststore// keytool -importcert -noprompt -alias databasezy -file databasezy-ca.pem \// -keystore databasezy-truststore.p12 -storetype PKCS12 -storepass changeitimport com.zaxxer.hikari.HikariConfig;import com.zaxxer.hikari.HikariDataSource;
public final class Db { public static HikariDataSource open() { var cfg = new HikariConfig(); cfg.setJdbcUrl("jdbc:mysql://mariadb-7f3k.us-east.databasezy.com:3306/app" + "?sslMode=VERIFY_IDENTITY" + "&trustCertificateKeyStoreUrl=file:databasezy-truststore.p12" + "&trustCertificateKeyStoreType=PKCS12" + "&trustCertificateKeyStorePassword=changeit"); cfg.setUsername("app"); cfg.setPassword(System.getenv("ZB_PASSWORD")); cfg.setMaximumPoolSize(10); return new HikariDataSource(cfg); }}Tested with: MariaDB 11.8 · MySQL Connector/J 9.1 · HikariCP 6.2
using MySqlConnector;
var cs = new MySqlConnectionStringBuilder{ Server = "mariadb-7f3k.us-east.databasezy.com", Port = 3306, Database = "app", UserID = "app", Password = Environment.GetEnvironmentVariable("ZB_PASSWORD"), SslMode = MySqlSslMode.VerifyFull, SslCa = "databasezy-ca.pem", MaximumPoolSize = 10,};await using var conn = new MySqlConnection(cs.ConnectionString);await conn.OpenAsync();await using var cmd = new MySqlCommand("select version()", conn);Console.WriteLine(await cmd.ExecuteScalarAsync());Tested with: MariaDB 11.8 · MySqlConnector 2.4
<?php$pdo = new PDO("mysql:host=mariadb-7f3k.us-east.databasezy.com;port=3306;dbname=app;charset=utf8mb4", "app", getenv("ZB_PASSWORD"), [ PDO::MYSQL_ATTR_SSL_CA => "databasezy-ca.pem", PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => true, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,]);echo $pdo->query("select version()")->fetchColumn();Tested with: MariaDB 11.8 · PHP 8.3 · PDO mysql (mysqlnd)
require "mysql2"
client = Mysql2::Client.new( host: "mariadb-7f3k.us-east.databasezy.com", port: 3306, username: "app", password: ENV.fetch("ZB_PASSWORD"), database: "app", sslca: "databasezy-ca.pem", sslverify: true, # verify chain and hostname ssl_mode: :verify_identity)puts client.query("select version() as v").first["v"]Tested with: MariaDB 11.8 · mysql2 0.5 · Ruby 3.3
mariadb --host mariadb-7f3k.us-east.databasezy.com --port 3306 --user app --password \ --ssl --ssl-ca=databasezy-ca.pem --ssl-verify-server-cert app
# orzb connect mariadb-7f3kTested with: MariaDB 11.8 · mariadb client 11.4
MySQL drivers work as they are; the snippets use them because they are the most common. The MariaDB-specific connectors (MariaDB Connector/J, Connector/Node.js and Connector/Python) work too: turn on TLS and server certificate verification in the same way. ORM guides that apply: Laravel, Rails, Django, SQLAlchemy, Prisma and Spring.
See Connecting to Databasezy for the CA bundle, the IP allow-list and credential rotation, which work the same for every engine.
Migrate in
Section titled “Migrate in”| Source | How | Continuous sync | Guide status |
|---|---|---|---|
| Amazon RDS and Aurora | Connection string | No | Coming soon · phase 2 |
| Self-hosted server | Connection string, Local tools (zb migrate --from local) | No | Available |
| Local files and dumps | File upload, Local tools (zb migrate --from local) | No | Available |
| Docker container | Local tools (zb migrate --from local) | No | Available |
| Another Databasezy instance | Instance to instance | No | Coming soon · phase 2 |
MariaDB migrations copy the schema and data with a logical dump and restore. There is no continuous sync yet, so plan a short write freeze on busy tables before cutover.
Coming from MySQL 8.x is a conversion: the engine conversions table lists what
preflight checks, such as JSON columns and the utf8mb4_0900_ai_ci collation.
How migrations work explains preflight, verification and cutover, and engine conversions covers moves between compatible engines.
Backups and restore
Section titled “Backups and restore”Backups are logical: a consistent mysqldump of every database, taken by the backup agent over the network and
streamed to object storage. The binary log is not archived yet, so there is no point-in-time recovery; a restore
returns the data as of a scheduled or manual backup.
MariaDB backups use mysqldump (logical dump). They run inside the instance's namespace, stream straight to the cell's object storage and are checksummed on upload. How often they run and how long they are kept follows your plan's backup policy. A backup is always taken before a resize or a version upgrade.
Point-in-time recovery is not available for MariaDB. A restore returns the data as of a scheduled or manual backup. Restores create a new instance by default and leave the original untouched; an in-place restore asks you to type the instance name and takes a pre-change backup first.
zb backups create mariadb-demo --label before-release # manual snapshotzb backups list mariadb-demozb backups restore mariadb-demo <backup-id> --name mariadb-demo-restorePause and scale to zero
Section titled “Pause and scale to zero”MariaDB can scale to zero. A paused instance has no running pods and bills no compute; its storage and backups are kept and billed as usual. Connections are refused until you resume it. On the Free plan an instance pauses by itself after 15 minutes without connections and wakes on the next one; the gateway holds that connection for up to 30 seconds while it starts.
zb instances pause mariadb-demozb instances resume mariadb-demoSee Pause and resume for schedules, wake times and billing while paused.
Limits, versions and lifecycle
Section titled “Limits, versions and lifecycle”Versions and lifecycle
Section titled “Versions and lifecycle”- Supported versions:
11.8,11.4,10.11. New instances default to11.8; pick another at creation with --engine-version or in the portal. - Minor and patch releases are applied for you in the maintenance window, always after a pre-change backup.
- New majors are added within 60 days of the upstream release. A major reaches end of life on Databasezy six months after upstream ends support, with notices 90, 30 and 7 days ahead.
- Moving between majors is a new instance plus an instance-to-instance migration, so you can test the new version before cutting over.
Each MariaDB series (10.11, 11.4, 11.8) is a major release with its own system tables, so moving to a newer series is a new instance plus a migration, never an in-place upgrade.
High availability and replicas
Section titled “High availability and replicas”With --ha, the instance runs a primary and at least one replica (--replicas sets how many, up to five) with
asynchronous GTID replication. If the primary fails, a replica is promoted automatically within seconds and the
instance host follows it. The -ro host (shown on the Connect tab) reads from the replicas, which refuse writes.
Replication is asynchronous, so a read on a replica can lag the primary slightly. Each replica runs on its own node.
Sizes and limits
Section titled “Sizes and limits”MariaDB runs on every size, including the Free plan's f0. The size sets the CPU, memory, storage ceiling and connection limit; the gateway refuses connections over the limit with a protocol error. Storage grows in steps up to the ceiling, and you can resize at any time.
| Size | vCPU | Memory | Max storage | Max connections | ≈ $ / month |
|---|---|---|---|---|---|
f0 | 0.063 | 512 MiB | 1 GB | 20 | Free |
s0 | 0.25 | 1 GiB | 20 GB | 60 | $10 |
s1 | 0.5 | 2 GiB | 50 GB | 100 | $15 |
s2 | 1 | 4 GiB | 200 GB | 200 | $60 |
m2 | 2 | 8 GiB | 500 GB | 400 | $110 |
m4 | 4 | 16 GiB | 1 TB | 800 | $210 |
l8 | 8 | 32 GiB | 4 TB | 1,500 | $410 |
l16 | 16 | 64 GiB | 8 TB | 3,000 | $960 |
xl32 | 32 | 128 GiB | 16 TB | 5,000 | $1,870 |
Full details, including hourly prices and burst CPU, are in the size catalogue; plan quotas are in limits and quotas.
MariaDB enforces the size’s connection limit at the gateway. Stored procedures, triggers, views and events are supported. Loading your own plugins or user-defined function libraries is not.
Licence
Section titled “Licence”Databasezy runs MariaDB under the GPL-2.0 licence, as listed in the engine catalogue. Your data and schemas are yours whatever the server's licence; the licence governs the server software we run.
The MariaDB server is GPL-2.0. That covers the server software, not applications that connect to it over the network. The client connectors have their own licences (mostly LGPL); check the one you ship with your application.
Security
Section titled “Security”- TLS on every connection. TLS 1.2 is the minimum and TLS 1.3 is preferred; plaintext is never
offered. Verify the server, not just the encryption: use
ssl-mode=VERIFY_IDENTITY. See TLS and the CA bundle. - IP allow-list. The gateway checks the client address before authentication, on every plan.
Manage it under Network → Allow-list in the portal or with
PUT /v1/orgs/{org}/instances/{id}/network. - Credentials. Generated inside the cell, shown once, never stored by the control plane. Rotate them with an overlap window so nothing breaks.
- Secure hosting. Secure placement (HIPAA-ready) is a per-instance option once your organization has signed the BAA: dedicated nodes, customer-managed keys and immutable backups. See Secure hosting and the BAA.
- Staff access. Databasezy staff cannot read your data without a grant you issue. See data confidentiality.
Can I use my MySQL driver?
Section titled “Can I use my MySQL driver?”Yes. MariaDB speaks the MySQL protocol, so mysql2, PyMySQL, go-sql-driver/mysql, Connector/J and the other MySQL
drivers connect without changes. Keep server certificate verification on.
MariaDB or MySQL?
Section titled “MariaDB or MySQL?”Pick the one your application is tested against. For a new project either works; both are on the Free plan, and MySQL offers continuous sync when you migrate in. Neither offers point-in-time recovery yet.
Is MariaDB on the Free plan?
Section titled “Is MariaDB on the Free plan?”Yes, on the f0 size.