TLS protects MySQL and MariaDB logins, queries, and result sets from passive capture on any network path between the client and the server. That matters as soon as connections leave the local Unix socket, because plain TCP exposes database credentials and application data to anyone who can observe the traffic.
The server side of a TLS-enabled database connection is controlled by the ssl_ca, ssl_cert, and ssl_key settings. Those files provide the certificate authority chain, the server certificate, and the matching private key that the database process loads during startup, while require_secure_transport blocks plain TCP sessions that do not negotiate TLS first.
Current releases add some shortcuts, but those shortcuts do not remove the need for deliberate certificate management. MySQL can auto-generate certificate files in the data directory when no TLS options are set, and MariaDB 11.4+ can enable verified zero-configuration TLS between current MariaDB clients and servers; a CA-managed certificate with the correct subjectAltName is still the safer choice when clients need predictable host validation, mixed MySQL/MariaDB fleets, or mutual TLS later. Examples below use the common Debian and Ubuntu layout under /etc/mysql/.
$ mysql -u root -p -e "SHOW GLOBAL VARIABLES LIKE 'have_ssl'; SHOW GLOBAL VARIABLES WHERE Variable_name IN ('ssl_ca','ssl_cert','ssl_key','require_secure_transport');"
Use mariadb instead of mysql on MariaDB packages that do not ship the compatibility client name. Non-empty ssl_ca, ssl_cert, or ssl_key values mean the server already has a configured TLS context.
MySQL can auto-discover ca.pem, server-cert.pem, and server-key.pem in the data directory. Replace those defaults when clients need VERIFY_IDENTITY against a real host name, because the auto-generated MySQL certificates do not carry a host-specific identity for that check.
$ sudo install -d -m 0750 -o mysql -g mysql /etc/mysql/ssl
$ sudo openssl genrsa -out /etc/mysql/ssl/ca-key.pem 4096 $ sudo openssl req -x509 -new -nodes -key /etc/mysql/ssl/ca-key.pem -sha256 -days 3650 -out /etc/mysql/ssl/ca-cert.pem -subj "/CN=Example Database CA" $ sudo openssl genrsa -out /etc/mysql/ssl/server-key.pem 2048 $ sudo openssl req -new -key /etc/mysql/ssl/server-key.pem -out /etc/mysql/ssl/server-req.pem -subj "/CN=db.example.net" $ sudo tee /etc/mysql/ssl/server-ext.cnf >/dev/null <<'EOF' subjectAltName=DNS:db.example.net,IP:192.0.2.15 extendedKeyUsage=serverAuth EOF $ sudo openssl x509 -req -in /etc/mysql/ssl/server-req.pem -CA /etc/mysql/ssl/ca-cert.pem -CAkey /etc/mysql/ssl/ca-key.pem -CAcreateserial -out /etc/mysql/ssl/server-cert.pem -days 3650 -sha256 -extfile /etc/mysql/ssl/server-ext.cnf Certificate request self-signature ok subject=CN = db.example.net
Replace db.example.net and 192.0.2.15 with the DNS name and IP address that clients really use. Use a certificate from an internal or public CA instead of a self-signed CA when the environment already has a trusted PKI.
Hostname validation depends on the subjectAltName extension. A Common Name alone is not enough for current TLS client verification.
$ sudo chown mysql:mysql /etc/mysql/ssl/server-key.pem /etc/mysql/ssl/server-cert.pem $ sudo chmod 600 /etc/mysql/ssl/server-key.pem $ sudo chmod 644 /etc/mysql/ssl/ca-cert.pem /etc/mysql/ssl/server-cert.pem
Protect the CA private key carefully. Move it off the database host after signing if the server does not also act as the certificate authority.
/etc/mysql/conf.d/ssl.cnf [mysqld] ssl_ca=/etc/mysql/ssl/ca-cert.pem ssl_cert=/etc/mysql/ssl/server-cert.pem ssl_key=/etc/mysql/ssl/server-key.pem require_secure_transport=ON
On MariaDB packages for Debian and Ubuntu, create /etc/mysql/mariadb.conf.d/z-custom-my.cnf instead and use a [mariadb] or [server] section. Keep custom TLS settings in a separate include file instead of editing the bundled 50-server.cnf directly.
require_secure_transport=ON rejects unencrypted TCP connections while still allowing secure local transports such as the Unix socket.
$ sudo systemctl restart mysql
Use sudo systemctl restart mariadb on MariaDB packages whose unit name is mariadb.
If the restart fails, inspect sudo journalctl -u mysql -b --no-pager or the MariaDB unit name before retrying. A wrong certificate path or unreadable key file usually prevents startup.
$ mysql -u root -p -e "SHOW GLOBAL VARIABLES LIKE 'have_ssl'; SHOW GLOBAL VARIABLES WHERE Variable_name IN ('ssl_ca','ssl_cert','ssl_key','require_secure_transport');"
Variable_name Value
have_ssl YES
Variable_name Value
require_secure_transport ON
ssl_ca /etc/mysql/ssl/ca-cert.pem
ssl_cert /etc/mysql/ssl/server-cert.pem
ssl_key /etc/mysql/ssl/server-key.pem
have_ssl=YES confirms that the server initialized TLS support. The file paths should match the include file that was just added.
$ mysql -u root -p -e "CREATE USER 'tlscheck'@'%' IDENTIFIED BY 'StrongPass123' REQUIRE SSL;" $ mysql --ssl-mode=VERIFY_IDENTITY --ssl-ca=/etc/mysql/ssl/ca-cert.pem -h db.example.net -u tlscheck -p -e "SHOW STATUS LIKE 'Ssl_cipher';" Enter password: +---------------+------------------------+ | Variable_name | Value | +---------------+------------------------+ | Ssl_cipher | TLS_AES_256_GCM_SHA384 | +---------------+------------------------+
On current MariaDB clients, the equivalent check is typically mariadb --ssl-ca=/etc/mysql/ssl/ca-cert.pem --ssl-verify-server-cert -h db.example.net -u tlscheck -p -e "SHOW STATUS LIKE 'Ssl_cipher';".
Replace StrongPass123 with a unique temporary password.
If Ssl_cipher is empty, the connection is not using TLS. Re-check the certificate paths, the server restart, and whether the client connected over TCP instead of the local socket.
$ mysql -u root -p -e "DROP USER 'tlscheck'@'%';"
To keep encryption mandatory for a real application account, use ALTER USER 'app'@'%' REQUIRE SSL; or stronger certificate-based requirements such as REQUIRE X509.