Skip to main content

Fixed: "The host name does not match the name on the certificate" with MySql.Data

· 5 min read
Jagdish Kumawat
Founder @ Dewiride

The host name does not match the name on the certificate is VerifyFull doing the one thing it adds: comparing Server= in your connection string with the names in the server's certificate. MySQL's automatic certificate has no name you could connect to, so against that certificate it can never pass.

What I Was Doing​

I was connecting with SslMode=VerifyFull to MySQL 9.7 in Docker, using the certificates it created when it first started, on MySql.Data 26.10.0:

Connection string
Server=127.0.0.1;Port=3306;…;SslMode=VerifyFull;SslCa=/Users/you/projects/mysql-connection-test/certs/ca.pem;SslCert=/Users/you/projects/mysql-connection-test/certs/client-cert.pem;SslKey=/Users/you/projects/mysql-connection-test/certs/client-rsa-key.pem
Terminal
dotnet run test-connection.cs

What I Expected​

A connection, because VerifyCA with the same CA had just worked.

What I Got​

Output
Unhandled exception. MySql.Data.MySqlClient.MySqlException (0x80004005): SSL Connection error
---> System.Exception: The host name does not match the name on the certificate

The test program stopping with SSL Connection error and The host name does not match the name on the certificate.

What I Checked​

The names on the certificate:

Terminal
docker compose exec mysql openssl x509 -in /var/lib/mysql/server-cert.pem -noout -subject -issuer -enddate -ext subjectAltName
Output
No extensions in certificate
subject=CN=MySQL_Server_9.7.4_Auto_Generated_Server_Certificate
issuer=CN=MySQL_Server_9.7.4_Auto_Generated_CA_Certificate
notAfter=Nov 3 06:02:30 2036 GMT

No Subject Alternative Name, and a common name nobody can connect to.

How the driver compares names. I gave a test server six certificates, and connected to each by localhost and by 127.0.0.1:

Certificate's namesServer=localhostServer=127.0.0.1
SAN: DNS:localhost, IP:127.0.0.1ConnectsConnects
SAN: DNS:localhostConnectsRefused
SAN: IP:127.0.0.1RefusedConnects
No SAN, common name localhostConnectsRefused
No SAN, common name 127.0.0.1RefusedConnects
SAN: DNS:db.example.com, common name localhostRefusedRefused

So the driver reads the SAN first, and it only looks at the common name when there's no SAN.

Why It Happens​

Server= has to appear in the certificate, exactly: a name for a name, and an IP address for an IP address. MySQL generates its certificate without knowing what you'll call the server, so it can't include your name.

The Fix​

Give the server a certificate with the names you connect by. If you're connecting to a managed server, use the host name your provider gave you, which is already in its certificate. For MySQL in Docker, sign a new one with the CA it already has:

Terminal
docker compose exec --user mysql mysql sh -c '
cd /var/lib/mysql &&
printf "subjectAltName=DNS:localhost,IP:127.0.0.1\n" > san.ext &&
openssl req -newkey rsa:2048 -nodes -keyout new-server-key.pem -out server.csr -subj "/CN=inventory-mysql" &&
openssl x509 -req -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -days 825 -extfile san.ext -out new-server-cert.pem &&
mv new-server-key.pem server-key.pem &&
mv new-server-cert.pem server-cert.pem &&
rm server.csr san.ext
'

Then tell MySQL to read it, as root, with no restart:

mysql>
ALTER INSTANCE RELOAD TLS;

After the Fix​

Terminal
dotnet run test-connection.cs
Output
Connected as inventory_app@% to MySQL 9.7.4
TLS: TLSv1.2

The test program printing Connected as inventory_app@% with TLS: TLSv1.2 under SslMode=VerifyFull, after giving the server a certificate with a Subject Alternative Name.

Common Mistakes​

MistakeWhat happensDo this instead
Falling back to VerifyCA for goodAny certificate from that CA passesFix the name, if the CA signs for others
Putting the name only in the common name, with a SAN for something elseThe SAN winsPut every name in the SAN
Connecting by IP with a certificate for a nameRefusedConnect by the name in the certificate
Forgetting ALTER INSTANCE RELOAD TLSMySQL keeps using the old certificateReload it, or restart

Troubleshooting​

SymptomLikely causeFix
Still refused after the new certificateMySQL hasn't reloaded itReload it
The certificate authority (CA) does not matchThe new certificate is signed by another CAThe fix
It works by localhost and fails from another computerThat host name isn't in the SANAdd it, and sign again

Conclusion​

VerifyFull needs Server= to be in the certificate's SAN. MySQL's automatic certificate has no usable name, so give it a certificate with yours. If you connect to a managed server, use the host name your provider gave you.

Additional Resources​

Stay Updated

Subscribe to our newsletter for the latest tutorials, tech insights, and developer news.

By subscribing, you agree to our privacy policy. Unsubscribe at any time.