Skip to main content

MySql.Data SslMode Options Explained: Disabled, Preferred, Required, VerifyCA and VerifyFull

· 7 min read
Jagdish Kumawat
Founder @ Dewiride

SslMode in a MySql.Data connection string decides two things: whether the connection is encrypted, and whether the driver checks who's on the other end. Required, the one most examples show, does the first and not the second. I tested each mode to see what it really does.

The Short Version​

SslModeEncrypted?Checks who signed the certificate?Checks the name on it?Needs
DisabledNoNoNoNothing
PreferredIf the server offers itNoNoNothing. It's the default
RequiredYesNoNoNothing
VerifyCAYesYesNoSslCa
VerifyFullYesYesYesSslCa, SslCert and SslKey

Use VerifyFull in production, or VerifyCA where only your own servers use that CA. The examples below use the one-file tester from How to Write a MySQL Connection String for .NET C#, which prints the account and the TLS version.

Disabled​

Terminal
export MYSQL_CONNECTION_STRING="Server=127.0.0.1;Port=3306;Database=inventory;User ID=inventory_app;Password=$(grep '^MYSQL_PASSWORD=' ../dewiride-inventory-api/.env | cut -d= -f2-);SslMode=Disabled"
dotnet run test-connection.cs
Output
Connected as inventory_app@% to MySQL 9.7.4
TLS: not used

No encryption: anyone on the network path can read the traffic. None, the old name for this, is gone: Oracle removed it in Connector/NET 9.6.0.

Preferred​

This is what you get if you leave SslMode out. It uses TLS when the server offers it:

Output
Connected as inventory_app@% to MySQL 9.7.4
TLS: TLSv1.2

The catch is the fallback. If a server, or something pretending to be one, doesn't offer TLS, it connects unencrypted without saying so. Oracle's description: "Use SSL if the server supports it, but allow connection in all cases."

Required​

"Always use SSL. Deny connection if server does not support SSL."

Output
Connected as inventory_app@% to MySQL 9.7.4
TLS: TLSv1.2

It looks the same as Preferred when all is well, but it won't fall back. What it doesn't do is check the certificate. To see what that means, I started a second MySQL on port 3307, with the same account and password, and its own certificate:

Connection string
Server=127.0.0.1;Port=3307;Database=inventory;User ID=inventory_app;Password=…;SslMode=Required
Output
Connected as inventory_app@% to MySQL 9.7.4
TLS: TLSv1.2

With SslMode=Required, the test program connecting to a second MySQL on port 3307, with TLS 1.2 and no complaint.

It connected, and sent its login. Encrypted, to the wrong server. An expired certificate gets the same free pass: Required connects to it without a word.

VerifyCA​

"Always use SSL. Validate the certificate authorities (CA), but tolerate a name mismatch." It needs the CA's file, which you can copy from the server:

Terminal
export MYSQL_CONNECTION_STRING="Server=127.0.0.1;Port=3306;Database=inventory;User ID=inventory_app;Password=$(grep '^MYSQL_PASSWORD=' ../dewiride-inventory-api/.env | cut -d= -f2-);SslMode=VerifyCA;SslCa=$PWD/certs/ca.pem"
dotnet run test-connection.cs
Output
Connected as inventory_app@% to MySQL 9.7.4
TLS: TLSv1.2

The same CA against that second server is refused:

Output
Unhandled exception. System.Exception: The provided key is invalid
---> Org.BouncyCastle.Security.InvalidKeyException: Public key presented not for certificate signature

With SslMode=VerifyCA and the real server's CA, the test program refusing the second server with The provided key is invalid.

How to Verify a MySQL Server Certificate in .NET C# with VerifyCA has the steps.

VerifyFull​

"Always use SSL. Fail if the host name is not correct." This adds a check that Server= is a name on the certificate. It matters when one CA signs for many servers, because VerifyCA would accept any of them. It also takes more setup, which How to Use VerifyFull with MySql.Data in .NET C# goes through.

Output
Connected as inventory_app@% to MySQL 9.7.4
TLS: TLSv1.2

Which to Use​

  • In production: VerifyFull. If your own server's certificate has the wrong name, VerifyCA is a good step on the way.
  • On your own computer, with MySQL in Docker: Required is fine while you're building, because the connection never leaves your machine.
  • Preferred: don't rely on it. If you want TLS, say so.
  • Disabled: only on a link you already trust, and only with a reason.

And to make the server insist as well, turn on require_secure_transport.

Common Mistakes​

MistakeWhat happensDo this instead
Treating Required as "secure"It's encrypted to whoever answersUse VerifyFull
Leaving out SslModePreferred falls back to no encryptionSet it
Going back to Required when a check failsYou've switched off what caught itFix the cause

Troubleshooting​

SymptomLikely causeFix
No file path has been provided … SslCaVerifyCA without a CA fileThe fix
No file path has been provided … SslCertVerifyFull wants a client pairThe fix
The host name does not match the name on the certificateVerifyFull found a wrong nameThe fix
Retrieval of the RSA public key is not enabledDisabled, and a first loginThe fix

Conclusion​

Required encrypts. VerifyCA adds who signed it. VerifyFull adds the name. Only the last two would notice the wrong server.

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.