Fixed: "ERROR 3888 (HY000): Failed to set up SSL" with "Unable to get private key" in MySQL
ERROR 3888: Failed to set up SSL with Unable to get private key means MySQL couldn't use the files you asked it to load. The good news is in the manual: a failed reload changes nothing, and the old certificate keeps running until you fix it.
What I Was Doing
I was replacing the certificate on MySQL 9.7, and I'd put the wrong key in place of server-key.pem. Then, as root:
ALTER INSTANCE RELOAD TLS;
What I Expected
The new certificate in use, with no restart.
What I Got
ERROR 3888 (HY000): Failed to set up SSL because of the following SSL library error: Unable to get private key

What I Checked
Whether MySQL still had working TLS. It did. MySQL's manual says the reload "rolls back with an error and has no effect if the configuration values do not permit creation of the new TLS context. The previous context values continue to be used for new connections."
Whether the key and the certificate belong together. Their public keys must match, and these two commands print a fingerprint of each:
openssl x509 -in server-cert.pem -noout -pubkey | openssl sha256
openssl pkey -in server-key.pem -pubout | openssl sha256
If the two lines differ, you have the wrong pair. Mine differed. A damaged key file gave me the same message, and so does a file MySQL can't read.
Why It Happens
To set up TLS, MySQL loads the certificate and the key, and the TLS library refuses a key that doesn't belong to that certificate.
The Fix
Put the matching key back. If you've made a new pair, make sure both files are from the same run, and readable by the mysql user. Then:
ALTER INSTANCE RELOAD TLS;
Query OK, 0 rows affected (0.001 sec)
Leave out NO ROLLBACK ON ERROR. With it, this failure turns TLS off rather than keeping the old certificate.
After the Fix
SHOW GLOBAL STATUS LIKE 'Ssl_server_not_after';
+----------------------+--------------------------+
| Variable_name | Value |
+----------------------+--------------------------+
| Ssl_server_not_after | Feb 8 06:04:42 2029 GMT |
+----------------------+--------------------------+
1 row in set (0.000 sec)
The date is the new certificate's, so MySQL is using it.

Common Mistakes
| Mistake | What happens | Do this instead |
|---|---|---|
| Restarting MySQL to "fix" it | With bad files, it starts without TLS | Fix the files first |
Using NO ROLLBACK ON ERROR | TLS goes off for new connections | Leave it out |
Mixing files from two runs of openssl | The key doesn't fit | Keep each pair together |
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| The fingerprints match, and it still fails | MySQL can't read the file | Check its owner and permissions |
| It works, but clients get the old certificate | They're connections from before the reload | New connections get the new one |
ERROR 1227 (42000): Access denied; you need (at least one of) the CONNECTION_ADMIN privilege(s) | Your account can't reload | Use an administrator |
Conclusion
ERROR 3888 from a reload means the new files don't work, and your old certificate is still running. Compare the fingerprints, fix the files, and reload.
Additional Resources
- ALTER INSTANCE —
RELOAD TLS, and how it rolls back. - openssl-pkey documentation — reading a key.
