How to Make MySQL Refuse Unencrypted Connections
A client can ask for TLS, but only the server can insist on it. require_secure_transport refuses any connection without it, for every account, so one wrong connection string can't quietly turn encryption off.
What You Need
MySQL 9.7 with TLS working, which is the default, and an administrator's account, such as root. Before you turn this on, make sure everything that connects can use TLS.
Step 1: Turn It On
SET PERSIST require_secure_transport = ON;
SHOW VARIABLES LIKE 'require_secure_transport';
Query OK, 0 rows affected (0.003 sec)
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| require_secure_transport | ON |
+--------------------------+-------+
1 row in set (0.001 sec)
SET PERSIST changes the running server and saves the setting in the data folder, so it survives a restart. SET GLOBAL wouldn't. It applies to new connections: an unencrypted session that was already open kept working when I turned this on.

Step 2: Test It
A client with TLS turned off, over TCP, is refused:
docker compose exec mysql mysql --user=inventory_app --password --protocol=TCP --host=127.0.0.1 --ssl-mode=DISABLED --execute "SELECT 1"
ERROR 3159 (HY000): Connections using insecure transport are prohibited while --require_secure_transport=ON.
The first time after a restart, the same command says ERROR 2061 instead. Either way, it's refused.
From a .NET app with SslMode=Disabled:
Unhandled exception. MySql.Data.MySqlClient.MySqlException (0x80004005): Authentication to host '127.0.0.1' for user 'inventory_app' using method 'caching_sha2_password' failed with message: Connections using insecure transport are prohibited while --require_secure_transport=ON.
---> MySql.Data.MySqlClient.MySqlException (0x80004005): Connections using insecure transport are prohibited while --require_secure_transport=ON.
With TLS, both work. Here's the .NET app with SslMode=Required:
Connected as inventory_app@% to MySQL 9.7.4
TLS: TLSv1.2
What It Doesn't Stop
A local socket counts as secure, so this still works inside the container:
docker compose exec mysql mysql --user=inventory_app --password --execute "SELECT 1 AS over_the_socket"
over_the_socket
1
So your Compose health check and docker compose exec sessions keep working. It's also not a check on who the server is: for that, clients need VerifyFull.
Step 3: Turn It Off, If You Need To
RESET PERSIST forgets the saved value, and the running server needs its own change:
RESET PERSIST require_secure_transport;
SET GLOBAL require_secure_transport = OFF;
SHOW VARIABLES LIKE 'require_secure_transport';
Query OK, 0 rows affected (0.002 sec)
Query OK, 0 rows affected (0.000 sec)
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| require_secure_transport | OFF |
+--------------------------+-------+
1 row in set (0.002 sec)
This or REQUIRE SSL?
require_secure_transport | ALTER USER … REQUIRE SSL | |
|---|---|---|
| Applies to | Every account | One account |
| A local socket | Allowed | Refused |
| Refusal | Says why | A plain Access denied |
For most servers, this one is simpler and clearer. How to Require TLS for One MySQL Account covers the other.
Common Mistakes
| Mistake | What happens | Do this instead |
|---|---|---|
Using SET GLOBAL to turn it on | A restart turns it off | Use SET PERSIST |
| Turning it on before checking your clients | Some stop connecting | Check SslMode in each one first |
| Testing over a socket | That was always allowed | Test over TCP |
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
ERROR 3159 | A client without TLS | The fix |
From .NET: Connections using insecure transport are prohibited | SslMode=Disabled or None | The fix |
| It's on again after you turned it off | You didn't RESET PERSIST | How to Undo SET PERSIST in MySQL |
| Nothing can connect over TCP | The server has no working TLS | The fix |
Conclusion
SET PERSIST require_secure_transport = ON makes the server refuse connections without TLS, and it survives a restart. Local sockets still work, so your own tools keep running.
Additional Resources
- Configuring Encrypted Connections as Mandatory — the setting.
- Persisted System Variables — how
SET PERSISTworks.
