Enable and require TLS for MySQL
/etc/mysql/mysql.conf.d/mysqld.cnf[mysqld]require_secure_transport = ONtls_version = TLSv1.2,TLSv1.3Or per-account, which is the safer way to roll it out:
ALTER USER 'app'@'10.0.1.%' REQUIRE SSL;Why it matters
Section titled “Why it matters”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.
Offering TLS is not requiring it
Section titled “Offering TLS is not requiring it”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.
The client half: sslmode
Section titled “The client half: sslmode”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 |
mysql --ssl-mode=VERIFY_IDENTITY --ssl-ca=/etc/mysql/ca.pem -h db.internal -u app -pREQUIRED 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.
Related
Section titled “Related”- Authentication plugins — get TLS working first.
- Bind to a private interface — if nothing crosses a wire, this matters less.