MySQL TLS and encryption monitoring: unencrypted connections and weak auth plugins

MySQL 8.0 generates self-signed certificates on startup and enables TLS by default, but this does not guarantee encrypted traffic. Clients must explicitly request TLS over TCP, and misconfigurations often leave sessions in plaintext without errors. Long-lived accounts frequently remain on mysql_native_password despite its deprecation in MySQL 8.0.34, while caching_sha2_password requires secure transport or RSA key exchange on first connection, causing sporadic authentication failures when client drivers lack encryption configuration. These risks are invisible to standard availability monitoring. This guide covers the status variables, Performance Schema tables, and account audits needed to detect unencrypted connections and weak authentication plugins in production.

flowchart TD
    A[Client connection] --> B{require_secure_transport}
    B -->|ON| C{Secure transport}
    B -->|OFF| D[Allowed: check encryption]
    C -->|No| E[Reject: Error 3159]
    C -->|Yes| F[Allowed: check plugin]
    D --> G{Account REQUIRE SSL}
    G -->|Yes and no TLS| H[Reject]
    G -->|No or TLS| F
    F -->|caching_sha2_password| I{First connect}
    I -->|No TLS/RSA| J[Auth failure]
    I -->|TLS or cached| K[Authenticated]
    F -->|mysql_native_password| L[Deprecated: audit]

What invisible exposure looks like

Unencrypted MySQL traffic usually produces no application errors: connections succeed, queries execute, and metrics look healthy. Exposure only becomes visible when you inspect the transport layer or audit account configuration.

  • Silent plaintext sessions: The server reports have_ssl = YES, but application connection strings omit TLS flags. In performance_schema.threads, TCP connections show CONNECTION_TYPE = 'TCP/IP' instead of 'SSL/TLS'. Health checks that open TCP, send SELECT 1, and close without negotiating TLS inflate the unencrypted connection count without carrying sensitive data, but application queries carrying credentials or user data over the same channel create real exposure.
  • Deprecated plugin persistence: Accounts created before an upgrade to MySQL 8.0 retain mysql_native_password. The server emits warning [MY-013360] to the error log on each use, but these warnings are often lost in log noise.
  • First-connect caching_sha2_password failures: After a password rotation, an application’s first connection attempt fails because the client driver lacks TLS or RSA configuration. The second attempt succeeds because the credential is now cached, making the failure transient and hard to reproduce.
  • Secure transport mismatches: An account with REQUIRE SSL rejects Unix socket connections even though sockets are treated as secure by the server-side require_secure_transport logic. This breaks local admin tools and containerized applications that rely on socket connections.

TLS connection signals to monitor

Global TLS counters and context

Do not rely on have_ssl alone. It indicates the server was built with SSL support and certificates are available, but does not prove clients are using them.

  • Ssl_accepts: Cumulative accepted SSL connections. Compare its growth to total new connections. If Ssl_accepts is flat while connection volume grows, traffic is likely falling back to plaintext.
  • Ssl_finished_accepts and Ssl_finished_connects: Successful SSL connections to the server and from the server to replication sources, respectively.
  • Tls_library_version: Reports the linked OpenSSL version. Confirms TLSv1.3 eligibility, which requires OpenSSL 1.1.1 or newer.

MySQL 8.0 also exposes current_tls_version, current_tls_cipher, and related current_tls_* status variables. These reflect the active TLS context after the last ALTER INSTANCE RELOAD TLS, not the static system variable values. If a runtime reload fails or the server falls back to compiled-in defaults, the current_tls_* values reveal the effective configuration.

Per-connection transport verification

To inspect active connections individually, query performance_schema.threads:

SELECT PROCESSLIST_USER,
       PROCESSLIST_HOST,
       CONNECTION_TYPE
FROM performance_schema.threads
WHERE TYPE = 'FOREGROUND';

CONNECTION_TYPE returns SSL/TLS, TCP/IP, or Unix socket. Any production TCP connection showing TCP/IP instead of SSL/TLS is a candidate for remediation.

For the current session, SHOW SESSION STATUS LIKE 'Ssl_version' returns an empty string when encryption is not in use. The same applies to Ssl_cipher. These are useful for ad-hoc verification from application client hosts.

Structured channel status

performance_schema.tls_channel_status (available since MySQL 8.0.21) provides a structured view of TLS properties per channel, such as mysql_main and mysql_admin. The PROPERTIES column includes the active protocol version and cipher suite, making it easier to parse than legacy global status variables. Query this table after rotating certificates or reloading TLS at runtime to confirm the new context took effect without requiring a restart.

Authentication plugin audit

Detecting deprecated and weak plugins

Inventory all accounts and their authentication plugins:

SELECT user, host, plugin, ssl_type
FROM mysql.user
WHERE user != '';

Flag any account using mysql_native_password. This plugin is deprecated as of MySQL 8.0.34. The server writes warning [MY-013360] to the error log on each connection that uses it. Oracle has not announced a specific removal version, but the deprecation signals approaching end-of-life.

For environments using roles, remember that role assignments do not change the underlying account plugin. Audit the base user accounts, not just active roles.

caching_sha2_password first-connect requirements

caching_sha2_password is the default authentication plugin in MySQL 8.0. The first connection after account creation or a password change must occur over a secure transport (TLS, Unix socket, or shared memory) or use RSA key-pair password exchange. After the first successful connection, the credential is cached and subsequent connections may succeed even without TLS.

This creates a specific failure signature: after credential rotation, applications that were previously working suddenly produce authentication errors on the first connection attempt, then recover on retry. If you see a spike in Aborted_connects correlated with a password change event but no corresponding persistent outage, check whether the client driver is configured to use TLS or whether the server has been configured with an RSA public key for the plugin.

If the client cannot use TLS and the server has not been configured for RSA key exchange, the authentication fails with an access-denied error. The error is transient from the application’s perspective because once any client successfully caches the credential, subsequent connections from that host may succeed depending on the driver’s caching behavior. This makes the failure appear random during connection pool churn or after failover events.

Account-level SSL requirements

Individual accounts can enforce TLS with REQUIRE SSL. However, REQUIRE SSL demands an SSL connection specifically. It rejects Unix socket and shared memory connections even though those transports are considered secure by the server-side require_secure_transport logic. Before applying REQUIRE SSL broadly, confirm that local tools and sidecar containers do not rely on socket connections.

Server configuration and enforcement checks

require_secure_transport

Setting require_secure_transport = ON causes MySQL to reject any connection that does not use a secure transport. The client receives error 3159 (Connections using insecure transport are prohibited). This is effective lockdown, but a blunt instrument. Before enabling it globally, verify that:

  • All application connection strings explicitly enable TLS or use Unix sockets.
  • All replicas using TCP are configured with SOURCE_SSL=1 (or MASTER_SSL=1 on older versions). Otherwise the replication I/O thread connects over plaintext TCP and is rejected immediately, breaking replication with error 3159 in the replica’s error log.
  • Monitoring and backup tools that connect over TCP support TLS.

tls_version and cipher configuration

tls_version controls which protocols the server permits. In MySQL 8.4 and later, the default is TLSv1.2,TLSv1.3; TLSv1 and TLSv1.1 were removed in MySQL 8.0.

Incorrect cipher configuration can disable encrypted connections entirely. Verify that have_ssl remains YES after any cipher changes.

Certificate expiry

Certificate expiry is a silent failure. The server continues running, but new TLS connections fail when clients enforce validity dates. This manifests as a sudden application-side connection storm while MySQL continues to accept TCP connections. Monitor the certificate files referenced by your TLS configuration. The current_tls_* global status variables show the active certificate paths, which helps confirm which files to check on disk. Schedule file-system validation of those PEM files as part of certificate lifecycle management.

Signals to monitor summary

SignalSourceWhy it mattersWarning sign
Ssl_acceptsSHOW GLOBAL STATUSTracks accepted SSL handshakesFlat or slow growth while total connections increase
CONNECTION_TYPEperformance_schema.threadsShows whether a session uses TCP, SSL, or socketActive TCP entries without SSL/TLS
Ssl_version (session)SHOW SESSION STATUSEmpty string means unencryptedEmpty value on TCP client connections
current_tls_versionSHOW GLOBAL STATUSEffective TLS protocol in useProtocol older than site policy
Tls_library_versionSHOW GLOBAL STATUSLinked OpenSSL versionOpenSSL too old for TLSv1.3
mysql_native_password accountsmysql.userDeprecated pluginAny production account still using it
caching_sha2_password first-connect failuresError log + Aborted_connectsRequires TLS or RSA on first connectionSporadic auth failures after credential rotation
require_secure_transportSHOW GLOBAL VARIABLESGlobal enforcement switchUnexpected error 3159 spikes after enablement
Certificate validityFile system / current_tls_*Expired certs break new TLS connectionsExpiration within planned rotation window

How Netdata helps

  • Correlate encryption adoption with connection health: Netdata tracks Ssl_accepts and total connection rates. A widening gap between total connections and SSL accepts signals plaintext leakage that standard health checks miss.
  • Link auth failures to TLS context changes: Correlate spikes in Aborted_connects with certificate rotation events or ALTER INSTANCE RELOAD TLS operations. This distinguishes caching_sha2_password first-connect failures from brute-force attacks.
  • Audit plugin distribution: Use Netdata’s custom query monitoring to run periodic audits of mysql.user plugin assignments and alert on any account using mysql_native_password.
  • Track TLS version drift: Monitor current_tls_version and Tls_library_version to detect configuration regressions or hosts running outdated OpenSSL builds.
  • How MySQL actually works in production: a mental model for operators: /guides/mysql/how-mysql-works-in-production/
  • MySQL Aborted_connects and Aborted_clients climbing: diagnosis: /guides/mysql/mysql-aborted-connections/
  • MySQL ERROR 1045 (28000): Access denied for user - diagnosis: /guides/mysql/mysql-access-denied-for-user/
  • MySQL adaptive hash index latch contention: high CPU, low throughput: /guides/mysql/mysql-adaptive-hash-index-latch-contention/
  • MySQL authentication failure spike: brute force vs broken credential rotation: /guides/mysql/mysql-auth-failure-rate/
  • MySQL binary logs filling the disk: expiry, lagging replicas, and purge: /guides/mysql/mysql-binary-log-disk-full/
  • MySQL InnoDB buffer pool hit ratio collapse: the cliff edge: /guides/mysql/mysql-buffer-pool-hit-ratio-collapse/
  • MySQL slow after restart: buffer pool warm-up and the cold cache: /guides/mysql/mysql-buffer-pool-not-warming-up/
  • MySQL innodb_buffer_pool_size tuning: 60-80% of RAM and when that breaks: /guides/mysql/mysql-buffer-pool-sizing/
  • MySQL Innodb_buffer_pool_wait_free > 0: buffer pool memory pressure: /guides/mysql/mysql-buffer-pool-wait-free/
  • MySQL InnoDB checkpoint age: the redo log capacity signal nobody watches: /guides/mysql/mysql-checkpoint-age-monitoring/
  • MySQL connection exhaustion: detection, diagnosis, and prevention: /guides/mysql/mysql-connection-exhaustion/