Encrypted SSL/TLS sessions protect MySQL and MariaDB traffic from passive capture, keeping credentials and query results confidential on untrusted networks.
When a client connects over TCP, the database server negotiates TLS during the initial handshake. The server presents a certificate, the client validates it against a trusted CA, and the session keys encrypt all subsequent protocol packets.
Many modern packages ship with TLS support and sometimes auto-generated certificates, but encryption without certificate validation still permits silent interception by an attacker with network position. Certificate files must be readable by the database service, private keys must remain tightly permissioned, and an incorrect ssl-key or ssl-cert path can prevent mysqld from starting.
Steps to enable SSL/TLS on MariaDB or MySQL server:
- Open a terminal with sudo privileges.
- Create a directory for TLS material at /etc/mysql/ssl.
$ sudo install -d -m 0750 -o mysql -g mysql /etc/mysql/ssl
- Generate a private key for a local certificate authority at /etc/mysql/ssl/ca-key.pem.
$ sudo openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096 -out /etc/mysql/ssl/ca-key.pem
Store the CA private key offline when certificate signing is complete.
- Create a self-signed CA certificate at /etc/mysql/ssl/ca-cert.pem.
$ sudo openssl req -x509 -new -key /etc/mysql/ssl/ca-key.pem -sha256 -days 3650 -out /etc/mysql/ssl/ca-cert.pem -subj "/C=US/ST=California/L=SanFrancisco/O=ExampleOrg/OU=Database/CN=ExampleOrg MySQL CA"
Only the CA certificate (not the CA private key) belongs on client hosts for server validation.
- Generate a private key for the database server at /etc/mysql/ssl/server-key.pem.
$ sudo openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out /etc/mysql/ssl/server-key.pem
- Create a server certificate signing request at /etc/mysql/ssl/server-req.pem.
$ sudo openssl req -new -key /etc/mysql/ssl/server-key.pem -out /etc/mysql/ssl/server-req.pem -subj "/C=US/ST=California/L=SanFrancisco/O=ExampleOrg/OU=Database/CN=db.example.net"
Hostname validation requires a subjectAltName; a Common Name alone is insufficient for VERIFY_IDENTITY in many TLS stacks.
- Create an OpenSSL extension file for the server certificate at /etc/mysql/ssl/server-ext.cnf.
$ sudo tee /etc/mysql/ssl/server-ext.cnf >/dev/null <<'EOF' [v3_server] basicConstraints=CA:FALSE keyUsage=digitalSignature,keyEncipherment extendedKeyUsage=serverAuth subjectAltName=DNS:db.example.net,IP:172.18.0.3 EOF
Replace the DNS and IP values with real database host details.
- Sign the server request to create /etc/mysql/ssl/server-cert.pem.
$ 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 -extensions v3_server Certificate request self-signature ok subject=C=US, ST=California, L=SanFrancisco, O=ExampleOrg, OU=Database, CN=db.example.net
- Generate a private key for an optional client certificate at /etc/mysql/ssl/client-key.pem.
$ sudo openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out /etc/mysql/ssl/client-key.pem
Client certificates are optional unless accounts enforce REQUIRE X509 or specific certificate attributes.
- Create a client certificate signing request at /etc/mysql/ssl/client-req.pem.
$ sudo openssl req -new -key /etc/mysql/ssl/client-key.pem -out /etc/mysql/ssl/client-req.pem -subj "/C=US/ST=California/L=SanFrancisco/O=ExampleOrg/OU=Database/CN=mysql-client"
- Create an OpenSSL extension file for the client certificate at /etc/mysql/ssl/client-ext.cnf.
$ sudo tee /etc/mysql/ssl/client-ext.cnf >/dev/null <<'EOF' [v3_client] basicConstraints=CA:FALSE keyUsage=digitalSignature extendedKeyUsage=clientAuth EOF
- Sign the client request to create /etc/mysql/ssl/client-cert.pem.
$ sudo openssl x509 -req -in /etc/mysql/ssl/client-req.pem -CA /etc/mysql/ssl/ca-cert.pem -CAkey /etc/mysql/ssl/ca-key.pem -CAcreateserial -out /etc/mysql/ssl/client-cert.pem -days 3650 -sha256 -extfile /etc/mysql/ssl/client-ext.cnf -extensions v3_client Certificate request self-signature ok subject=C=US, ST=California, L=SanFrancisco, O=ExampleOrg, OU=Database, CN=mysql-client
- Set ownership of the server key/certificate to the mysql user.
$ sudo chown mysql:mysql /etc/mysql/ssl/server-key.pem /etc/mysql/ssl/server-cert.pem
Keep client key material root-owned on the server, or copy it off-host for client use.
- Restrict permissions on private keys.
$ sudo chmod 600 /etc/mysql/ssl/ca-key.pem /etc/mysql/ssl/server-key.pem /etc/mysql/ssl/client-key.pem
- Set read permissions on certificate-related files.
$ sudo chmod 644 /etc/mysql/ssl/ca-cert.pem /etc/mysql/ssl/server-cert.pem /etc/mysql/ssl/client-cert.pem /etc/mysql/ssl/server-req.pem /etc/mysql/ssl/client-req.pem
- Add the TLS paths under the mysqld section in /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
MariaDB commonly uses /etc/mysql/mariadb.conf.d/50-server.cnf for server settings.
An incorrect ssl-key path or unreadable key file can prevent the database service from starting.
- Restart the mysql service.
$ sudo docker restart sg-mysql sg-mysql
On non-container hosts, use sudo systemctl restart mysql (or mariadb on MariaDB packages).
- Check the service is responding after restart.
$ mysqladmin -u root -p ping mysqld is alive
Use journalctl for startup errors: sudo journalctl -u mysql -b --no-pager.
- Confirm the server loaded the configured TLS files.
$ mysql --table -u root -p -e "SHOW VARIABLES WHERE Variable_name IN ('ssl_ca','ssl_cert','ssl_key');" +---------------+--------------------------------+ | Variable_name | Value | +---------------+--------------------------------+ | ssl_ca | /etc/mysql/ssl/ca-cert.pem | | ssl_cert | /etc/mysql/ssl/server-cert.pem | | ssl_key | /etc/mysql/ssl/server-key.pem | +---------------+--------------------------------+A non-empty Ssl_cipher value confirms an encrypted session.
- Create a minimal test account that requires SSL.
$ mysql -u root -p -e "CREATE USER 'tlscheck'@'172.18.0.3' IDENTIFIED BY 'STRONG_PASSWORD_HERE' REQUIRE SSL;" Query OK, 0 rows affected
Replace STRONG_PASSWORD_HERE with a unique password.
- Verify a TLS cipher is negotiated for a TCP connection.
$ mysql --ssl-mode=VERIFY_CA --ssl-ca=/etc/mysql/ssl/ca-cert.pem -h 172.18.0.3 -u tlscheck -p -e "SHOW STATUS LIKE 'Ssl_cipher';" Enter password: +---------------+------------------------+ | Variable_name | Value | +---------------+------------------------+ | Ssl_cipher | TLS_AES_256_GCM_SHA384 | +---------------+------------------------+
Mutual TLS uses --ssl-cert plus --ssl-key with an account that enforces REQUIRE X509.
Account-level enforcement uses ALTER USER 'app'@'%' REQUIRE SSL;.
- Remove the test account.
$ mysql -u root -p -e "DROP USER 'tlscheck'@'172.18.0.3';" Query OK, 0 rows affected
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
