Skip to content

Enable and require TLS for MySQL

Severity: highApplies to: MySQL 8.4 LTSApplies to: MariaDB 11.x / 12.x
The fix/etc/mysql/mysql.conf.d/mysqld.cnf
[mysqld]
require_secure_transport = ON
tls_version = TLSv1.2,TLSv1.3

Or per-account, which is the safer way to roll it out:

ALTER USER 'app'@'10.0.1.%' REQUIRE SSL;

Without TLS, every query, every result row and every credential exchange crosses the network in the clear. On MySQL that includes the authentication handshake — and caching_sha2_password in particular will not send credentials over an unencrypted connection unless an RSA key exchange happens first, which is why migrating auth before fixing TLS produces confusing failures.

MySQL already generates certificates for you

Section titled “MySQL already generates certificates for you”

This is the part that surprises people, in a good way.

MySQL 8 creates a self-signed CA and server certificate at initialisation and enables TLS automatically. You do not need to obtain a certificate to get encryption working. The files land in the data directory (ca.pem, server-cert.pem, server-key.pem) and the server uses them without any configuration.

So on a modern MySQL, TLS is almost certainly already available. The problem is that available is not required.

Those auto-generated certificates are self-signed, which matters for what the client can verify — see below. They’re fine for encryption; they cannot prove which server you reached.

Same trap as Postgres and Redis, and worth stating plainly because MySQL’s automatic setup makes it easier to believe you’re done.

By default the server accepts both encrypted and unencrypted connections. A client that asks for TLS gets it; a client that doesn’t, connects in plaintext and is accepted silently. Since most modern clients default to preferring TLS, this usually looks fine — right up until the one legacy client that doesn’t.

require_secure_transport = ON refuses any unencrypted TCP connection outright. Unix socket connections are still allowed, since they never touch a network.

A server requiring TLS stops eavesdropping. Only the client can verify which server it reached:

Client mode Encrypts Verifies CA Verifies hostname
PREFERRED (default) if available no no
REQUIRED yes no no
VERIFY_CA yes yes no
VERIFY_IDENTITY yes yes yes
Terminal window
mysql --ssl-mode=VERIFY_IDENTITY --ssl-ca=/etc/mysql/ca.pem -h db.internal -u app -p

REQUIRED stops passive interception and does nothing against an active machine-in-the-middle. VERIFY_IDENTITY is the one that means what people think REQUIRED means — and it needs a certificate whose name matches the host, which the auto-generated self-signed one will not.