A production MariaDB TLS configuration must do more than make an Ssl_version value appear. It must protect traffic from passive inspection, verify that clients reached the intended server, handle private keys safely, reject unencrypted connections where required, and survive certificate renewal without an avoidable outage.
The most common incomplete setup enables encryption on the server but disables hostname verification on clients. That protects against simple packet capture yet may still allow a client to trust the wrong endpoint. Another common failure enables require_secure_transport before every application, backup job, exporter, and administrative client has a trusted CA bundle. The result is a self-inflicted outage.
This guide builds TLS from a private certificate authority through server configuration, client verification, per-account requirements, global enforcement, monitoring, renewal, troubleshooting, and rollback. Examples use Ubuntu 24.04 paths and a server name of db01.example.net. Replace all names, addresses, validity periods, and paths with values governed by your organization.
Understand what MariaDB TLS protects
TLS provides three related controls:
- Confidentiality: observers cannot read SQL statements, result sets, or credentials in transit.
- Integrity: modification of encrypted traffic is detected.
- Server authentication: a verifying client confirms that the certificate is trusted and belongs to the hostname it requested.
Mutual TLS can additionally authenticate a client certificate. MariaDB can require any TLS session, a valid X.509 client certificate, or specific certificate subject and issuer values for an account.
TLS does not replace account passwords, least-privilege grants, firewalls, patching, or encryption at rest. It protects the network channel. A stolen database credential can still be abused through an approved network path, and a compromised server can read data after decryption.
MariaDB documentation and configuration retain many ssl_ names for compatibility, although modern deployments use TLS rather than the obsolete SSL protocols. In this article, “SSL option” refers to that historical naming; the security objective is TLS.
Plan the certificate model before generating files
For production, use certificates issued by an internal public key infrastructure or a trusted organizational CA. A public CA may be appropriate for publicly resolvable names, but database endpoints are commonly private. Self-signed leaf certificates are acceptable for isolated testing when clients explicitly trust the exact certificate, not as an unmanaged production shortcut.
Document these decisions:
| Decision | Production recommendation |
|---|---|
| Server identity | Stable DNS name clients actually use |
| Subject Alternative Name | Include every approved DNS name; add IP only if clients connect by IP |
| Issuer | Managed internal or public CA |
| Private-key owner | MariaDB service account only |
| Distribution | CA certificates to clients; never distribute server private key |
| Renewal | Automated with staged validation and overlap |
| Revocation | CA process and CRL support where required |
| Enforcement | Per-account first, global after complete inventory |
Hostname verification compares the requested endpoint with the certificate identity. If the certificate covers db01.example.net but an application connects to 10.20.30.10, verification can fail unless that IP address is included as an IP SAN. Prefer a stable DNS name and issue the certificate for that name.
Inventory every TCP client before enforcement:
- Application services and connection pools.
- Migration pipelines and scheduled jobs.
- Logical and physical backup tools.
- Monitoring exporters and health checks.
- Replicas, proxies, and change-data-capture clients.
- Administrative scripts, desktop tools, and emergency procedures.
Local Unix-socket connections count as secure transport for require_secure_transport; they do not use TLS because traffic does not cross TCP. Record this distinction so local administrative access is not mistaken for an encryption failure.
Inspect the installed server and TLS library
Capture the release and current state before changing anything:
mariadb --version
sudo mariadb -e "SELECT VERSION();"
sudo mariadb -e "SHOW GLOBAL VARIABLES WHERE Variable_name IN (
'have_ssl','ssl_ca','ssl_cert','ssl_key','tls_version','require_secure_transport'
);"
sudo mariadb -e "SHOW GLOBAL STATUS LIKE 'Ssl_%';"
Also inspect the server's linked TLS library and option-file order:
mariadbd --version
ldd "$(command -v mariadbd)" | grep -Ei 'ssl|crypto|gnutls|wolf' || true
mariadbd --help --verbose 2>/dev/null | sed -n '/Default options/,/Variables and options/p'
Underlying library capabilities affect supported protocol versions, ciphers, certificate revocation options, and hostname verification. Do not assume that every MariaDB client binary on every operating system behaves identically.
Version defaults also matter. MariaDB's current documentation says server certificate verification is enabled by default in newer client generations associated with MariaDB 11.4 and later, while older clients require explicit verification. Ubuntu 24.04 distribution packages are commonly from the MariaDB 10.11 family. Configure the CA and verification option explicitly so security does not depend on a changing default.
Build a test certificate authority safely
The following OpenSSL workflow is suitable for a controlled lab and illustrates the required files. A production organization should normally use its managed CA rather than keep a long-lived CA private key on the database server.
Create the CA in a protected administration environment, not under the MariaDB data directory:
umask 077
openssl genpkey -algorithm RSA
-pkeyopt rsa_keygen_bits:4096
-out lab-ca-key.pem
openssl req -x509 -new -sha256
-key lab-ca-key.pem
-days 3650
-subj '/CN=Example Lab MariaDB CA/O=Example Lab'
-out lab-ca-cert.pem
Generate the server key and certificate-signing request:
umask 077
openssl genpkey -algorithm RSA
-pkeyopt rsa_keygen_bits:3072
-out db01-key.pem
openssl req -new -sha256
-key db01-key.pem
-subj '/CN=db01.example.net/O=Example Lab'
-out db01.csr
Create an extension file named db01.ext:
basicConstraints=critical,CA:FALSE
keyUsage=critical,digitalSignature,keyEncipherment
extendedKeyUsage=serverAuth
subjectAltName=DNS:db01.example.net,DNS:mariadb.example.net
Sign the request:
openssl x509 -req -sha256
-in db01.csr
-CA lab-ca-cert.pem
-CAkey lab-ca-key.pem
-CAcreateserial
-days 365
-extfile db01.ext
-out db01-cert.pem
Inspect rather than trust the command alone:
openssl verify -CAfile lab-ca-cert.pem db01-cert.pem
openssl x509 -in db01-cert.pem -noout
-subject -issuer -serial -dates -ext subjectAltName
openssl pkey -in db01-key.pem -check -noout
Do not copy lab-ca-key.pem to the MariaDB host or any client. The server needs its leaf private key, leaf certificate, and CA certificate. Clients normally need only the CA certificate. Protect backups of the CA key according to your PKI policy.
Install the server certificate and private key
Create a dedicated directory outside the web root and restrict ownership:
sudo install -d -o root -g mysql -m 0750 /etc/mysql/tls
sudo install -o root -g mysql -m 0640 db01-key.pem /etc/mysql/tls/server-key.pem
sudo install -o root -g mysql -m 0644 db01-cert.pem /etc/mysql/tls/server-cert.pem
sudo install -o root -g mysql -m 0644 lab-ca-cert.pem /etc/mysql/tls/ca-cert.pem
The MariaDB service must read the private key, but ordinary local users must not. Avoid world-readable key permissions. On systems using AppArmor or SELinux, a custom path may also require an approved policy or file context. Ubuntu's /etc/mysql hierarchy is generally easier to govern than an arbitrary home directory.
Confirm file metadata without printing private-key contents:
sudo namei -l /etc/mysql/tls/server-key.pem
sudo stat -c '%U %G %a %n' /etc/mysql/tls/*
sudo -u mysql test -r /etc/mysql/tls/server-key.pem
Never paste the private key into a ticket, terminal transcript, container image, or Git repository. If exposure is suspected, generate a new key and revoke or replace the certificate; changing filesystem permissions afterward does not undo disclosure.
Configure MariaDB Server
On Debian and Ubuntu, create a late-loading custom file rather than editing a package-owned default:
sudoedit /etc/mysql/mariadb.conf.d/z-tls.cnf
Add:
[mariadb]
ssl_ca = /etc/mysql/tls/ca-cert.pem
ssl_cert = /etc/mysql/tls/server-cert.pem
ssl_key = /etc/mysql/tls/server-key.pem
# Choose versions supported by the server and all approved clients.
tls_version = TLSv1.2,TLSv1.3
Do not enable require_secure_transport yet. First prove that the server starts with the new files and every client can verify the certificate.
Check parsed options and validate configuration using the facilities available in the installed release:
my_print_defaults mariadb server mysqld
sudo systemctl restart mariadb
sudo systemctl --no-pager --full status mariadb
sudo journalctl -u mariadb -n 100 --no-pager
A restart is required for certificate path changes and most static TLS settings. Schedule this through the normal change process. If the service fails, inspect the journal before modifying multiple variables. Common causes are an unreadable private key, malformed PEM file, unsupported protocol selection, wrong path, or mandatory-access-control denial.
Verify server capability through the local socket:
SHOW GLOBAL VARIABLES LIKE 'have_ssl';
SHOW GLOBAL VARIABLES WHERE Variable_name IN
('ssl_ca','ssl_cert','ssl_key','tls_version','require_secure_transport');
have_ssl should indicate that TLS is available. A configured path alone is not proof that a remote session is encrypted.
Distribute trust to clients
Transfer only the CA certificate through an authenticated configuration-management channel. Install it with read-only permissions appropriate for the service:
sudo install -d -o root -g root -m 0755 /etc/myapp/tls
sudo install -o root -g root -m 0644 lab-ca-cert.pem /etc/myapp/tls/mariadb-ca.pem
openssl x509 -in /etc/myapp/tls/mariadb-ca.pem -noout -subject -issuer -fingerprint -sha256
Compare the SHA-256 fingerprint with a value obtained through an independent trusted channel. A CA bundle delivered by the same compromised endpoint it is meant to authenticate provides weak assurance.
Applications should set all of these explicitly:
- TLS enabled or required, not “preferred with plaintext fallback.”
- CA file or trusted system store.
- Hostname verification enabled.
- Connection hostname matching a certificate SAN.
- A minimum protocol policy compatible with the runtime driver.
Driver option names differ between Java, Go, PHP, Python, Perl, Node.js, and native connectors. Use documentation for the exact connector and version. Do not translate MariaDB command-line options blindly into an application URL.
Test an explicitly verified client connection
From an authorized client host, connect by the DNS name present in the certificate:
mariadb
--host=db01.example.net
--user=orders_api
--password
--ssl-ca=/etc/myapp/tls/mariadb-ca.pem
--ssl-verify-server-cert
--tls-version=TLSv1.2,TLSv1.3
--database=orders
The password prompt avoids putting a secret in the process list or shell history. Within that exact session, verify negotiated properties:
SHOW SESSION STATUS LIKE 'Ssl_version';
SHOW SESSION STATUS LIKE 'Ssl_cipher';
SELECT USER(), CURRENT_USER();
An empty Ssl_version indicates that session is not using TLS. A nonempty protocol and cipher prove encryption was negotiated, but hostname verification must still be enforced by the client configuration.
Run deliberate negative tests from a safe environment:
- Connect with a hostname not present in the certificate SAN; verification should fail.
- Use an unrelated CA file; chain validation should fail.
- Temporarily test a client with an unsupported TLS version; negotiation should fail.
- After account enforcement, attempt plaintext; MariaDB should reject it.
Do not weaken production verification to make a negative test pass. Fix DNS, certificate identity, CA distribution, time synchronization, or client configuration.
Require TLS for selected MariaDB accounts
Per-account enforcement is a controlled first rollout. Require encryption for one service identity:
ALTER USER 'orders_api'@'10.20.30.25' REQUIRE SSL;
SHOW CREATE USER 'orders_api'@'10.20.30.25';
SHOW GRANTS FOR 'orders_api'@'10.20.30.25';
REQUIRE SSL requires a TLS connection but does not require the client to present an X.509 certificate. Server authentication still depends on the client verifying the server certificate.
Where mutual TLS is part of the design, MariaDB supports stricter account requirements:
ALTER USER 'orders_api'@'10.20.30.25' REQUIRE X509;
The client must then provide a valid certificate and private key trusted by the server. For still tighter matching, REQUIRE SUBJECT and REQUIRE ISSUER can bind an account to certificate attributes. Copy the exact distinguished-name representation from inspected certificates; formatting mismatches are a frequent source of denial.
Mutual TLS increases assurance but also adds client-key issuance, distribution, rotation, revocation, and incident-response duties. Do not enable it without an operational lifecycle.
To remove an account TLS requirement during an approved rollback:
ALTER USER 'orders_api'@'10.20.30.25' REQUIRE NONE;
This is a security downgrade. Use it only as a documented temporary rollback while network controls remain restrictive.
Enforce secure transport globally
After every TCP client has passed verified TLS testing, enable global enforcement. MariaDB introduced require_secure_transport in 10.5.2. It rejects insecure network connections while allowing secure transports such as TLS and local Unix sockets.
Test the dynamic change during a controlled window:
SET GLOBAL require_secure_transport = ON;
SHOW GLOBAL VARIABLES LIKE 'require_secure_transport';
This runtime change does not survive restart. Once validated, add it to the server configuration:
[mariadb]
require_secure_transport = ON
Then restart in a planned window and verify both encrypted TCP clients and local administrative socket access.
Before enforcement, search configuration and automation for overlooked clients. Health checks that use raw TCP only are unaffected because they do not authenticate, but checks that log in without TLS will fail. Old exporters, replication channels, backup scripts, and cron jobs deserve explicit tests.
If an outage begins immediately after the dynamic change, an administrator connecting through the local Unix socket can roll it back:
SET GLOBAL require_secure_transport = OFF;
If it was persisted, remove or comment the setting through the change process before the next restart. Do not leave production indefinitely in an unknown mixed mode; repair clients and re-enable enforcement.
Monitor TLS usage without inventing certainty
Inspect session-level status within client validation and global TLS counters for operational trends:
SHOW GLOBAL STATUS WHERE Variable_name IN
('Ssl_accepts','Ssl_finished_accepts','Ssl_accept_renegotiates');
Status counters are not a complete per-user audit. A growing handshake count proves TLS activity exists, not that every relevant client verifies the correct hostname. Combine server metrics with application configuration review, connection tests, and account/global enforcement.
Monitor certificate lifetime outside MariaDB:
openssl x509 -in /etc/mysql/tls/server-cert.pem -noout -dates
An automated check can parse notAfter and alert well before expiry. Choose thresholds that leave time for issuance, staged deployment, rollback, and change approval. Also monitor DNS, system time, MariaDB restart failures, and client TLS errors.
Troubleshoot common MariaDB TLS failures
MariaDB does not start after adding certificates
Check the journal and file access first:
sudo journalctl -u mariadb -b --no-pager
sudo -u mysql test -r /etc/mysql/tls/server-key.pem
openssl x509 -in /etc/mysql/tls/server-cert.pem -noout -subject -dates
openssl pkey -in /etc/mysql/tls/server-key.pem -check -noout
Validate that the certificate and private key match by comparing public-key digests:
openssl x509 -in /etc/mysql/tls/server-cert.pem -pubkey -noout |
openssl pkey -pubin -outform DER | openssl sha256
openssl pkey -in /etc/mysql/tls/server-key.pem -pubout -outform DER |
openssl sha256
The digests should match. Do not print the private key.
Certificate verify failed
Check the trust chain, certificate dates, system clocks, and requested hostname:
getent ahosts db01.example.net
timedatectl status
openssl verify -CAfile /etc/myapp/tls/mariadb-ca.pem db01-cert.pem
openssl x509 -in db01-cert.pem -noout -dates -ext subjectAltName
Do not solve verification errors with --disable-ssl-verify-server-cert. That removes server identity verification. Reissue the certificate with correct SANs or connect through the intended DNS name.
TLS works with the CLI but not the application
The application driver may use a different CA store, option name, hostname, or protocol library. Log sanitized driver configuration, confirm the runtime connector version, and reproduce with a minimal program using the same connector. A successful mariadb CLI test only proves that client binary works.
Account receives Access denied only without TLS
Inspect the account definition:
SHOW CREATE USER 'orders_api'@'10.20.30.25';
SELECT USER(), CURRENT_USER();
REQUIRE SSL or stricter X.509 conditions may be working exactly as intended. Configure TLS on the client rather than changing its password.
No shared cipher or protocol version
Compare server tls_version, client options, and underlying libraries. A legacy runtime may not support the minimum protocol. Upgrade that client instead of enabling obsolete protocols globally. Be cautious with explicit cipher lists: TLS 1.2 and TLS 1.3 use different configuration mechanisms in some libraries.
The certificate renewed but clients still see the old one
Confirm which endpoint they reach. A load balancer, proxy, or different database node may terminate TLS with another certificate. MariaDB may require a restart or supported certificate reload procedure depending on release and configuration. Verify a new connection, because existing sessions can continue using parameters negotiated earlier.
Renew certificates without an outage
Treat renewal as a repeatable deployment, not a last-minute file replacement:
- Request a new certificate with the same approved SAN set and a new private key where policy requires it.
- Verify chain, dates, key match, SANs, and key permissions offline.
- Test the certificate on a staging instance with representative old and new clients.
- Preserve the previous certificate and key in a protected rollback package.
- Deploy atomically through configuration management.
- Restart or reload according to the exact MariaDB release documentation.
- Open a new verified client session and inspect
Ssl_version, cipher, and certificate identity. - Monitor application errors before completing the change.
- Retire the previous key securely after the rollback window.
When rotating the CA, distribute a bundle containing both old and new CA certificates before switching the server leaf certificate. After all endpoints use the new chain and rollback is no longer needed, remove the old CA from clients. Changing server certificate and client trust simultaneously creates an unnecessary coordination risk.
Production checklist
- Use a stable DNS name included in the certificate SAN.
- Keep CA private keys off database and application hosts.
- Limit read access to the MariaDB server private key.
- Configure TLS protocol versions supported by every approved client.
- Distribute only trust certificates to ordinary clients.
- Enable hostname verification explicitly across version differences.
- Validate session
Ssl_versionandSsl_cipheron real client paths. - Run wrong-host, wrong-CA, and plaintext negative tests.
- Apply
REQUIRE SSLper account before global enforcement. - Enable
require_secure_transportonly after inventory and staged rollout. - Monitor certificate expiry and renewal failures.
- Keep a tested socket-based administrative rollback path.
- Review TLS again after proxy, driver, replica, or topology changes.
FAQ
Is MariaDB SSL the same as TLS?
MariaDB retains many ssl_ option and status names for compatibility, but secure modern connections use TLS. Obsolete SSL protocols should not be enabled.
Does --ssl verify the MariaDB server certificate?
Behavior depends on the client version. Configure a trusted CA and hostname verification explicitly instead of relying on a default that changed across releases.
What does REQUIRE SSL do for a MariaDB user?
It requires that account to connect over TLS. It does not require a client certificate; use REQUIRE X509 or stricter subject and issuer conditions for mutual TLS.
Does require_secure_transport break local socket login?
No. MariaDB considers a Unix socket a secure transport. The setting primarily rejects insecure TCP connections.
How can I prove a MariaDB session uses TLS?
Run SHOW SESSION STATUS LIKE 'Ssl_version' and SHOW SESSION STATUS LIKE 'Ssl_cipher' inside that session. Also verify that the client checks the server hostname against a trusted certificate.
Should I connect by IP address when using TLS?
Prefer the stable DNS name listed in the certificate SAN. If clients must use an IP, the certificate should contain that address as an IP SAN.
Can I use a self-signed certificate in production?
It can encrypt traffic if distributed and pinned correctly, but managed CA issuance provides a better renewal, trust, and revocation lifecycle. Self-signed certificates are most suitable for controlled testing.
Must MariaDB restart after certificate renewal?
The procedure depends on release and configuration. Follow the documentation for the installed version and always verify the new certificate through a new client connection.
Conclusion
A reliable MariaDB TLS configuration establishes trust before it enforces encryption. Issue the server certificate for the name clients use, protect its private key, distribute the CA independently, and make clients verify both chain and hostname. Then prove negotiated TLS through real sessions and negative tests.
Roll out account-level requirements before enabling require_secure_transport globally, keep a local socket rollback path, and treat renewals as tested deployments. This approach closes plaintext and impersonation risks without turning a security improvement into an application outage.
Suggested Internal Links
- Secure a New MariaDB Server: Production Hardening Guide
- Configure MariaDB Remote Access Without Exposing It
- MariaDB Users and Grants: A Least-Privilege Production Guide
- MariaDB Authentication Plugins Explained for Linux Admins
- Configure the MariaDB Firewall and Network Controls
- Troubleshoot MariaDB Connection Refused and Access Denied