Supported MySQL Authentication Methods in the Go-MySQL-Driver: A Complete Guide to Server Negotiation

The go-sql-driver/mysql supports six authentication plugins—caching_sha2_password, mysql_native_password, sha256_password, mysql_old_password, mysql_clear_password, and client_ed25519—negotiating the method through a handshake protocol that defaults to mysql_native_password when the server specifies no plugin, with automatic fallback to RSA-encrypted full authentication for MySQL 8+ caching_sha2_password fast-path failures.

The go-sql-driver/mysql (imported as github.com/go-sql-driver/mysql) is the standard MySQL driver for Go's database/sql package. Understanding which MySQL authentication methods it supports and how it negotiates these methods with the server is critical for securing database connections across MySQL 5.6+, MySQL 8.0+, and MariaDB deployments.

Supported MySQL Authentication Plugins

The driver implements a switch-case selector in auth.go lines 279‑389 that handles each MySQL authentication plugin according to the MySQL protocol:

  • caching_sha2_password – The MySQL 8+ default. The driver first attempts the fast path using scrambleSHA256Password. If the server responds with cachingSha2PasswordPerformFullAuthentication, it falls back to RSA-encrypted password transmission or clear-text over TLS.
  • mysql_native_password – The default for MySQL 5.x and the driver's fallback method (defaultAuthPlugin). Uses scramblePassword with SHA-1 hashing.
  • sha256_password – Supported for MySQL 5.6+. Requires either TLS or RSA public-key encryption to transmit the password securely.
  • mysql_old_password – Pre-4.1 authentication using scrambleOldPassword. Only enabled when AllowOldPasswords is set to true.
  • mysql_clear_password – Transmits the password in clear text. Only enabled when AllowCleartextPasswords is set to true.
  • client_ed25519 – MariaDB-specific plugin using Ed25519 signatures via the authEd25519 function.

If the server does not propose a plugin or the requested plugin fails, the driver retries using the defaultAuthPlugin constant defined in const.go line 16.

How Authentication Is Negotiated with the Server

The negotiation process follows a strict protocol flow orchestrated by connector.connect in connector.go and the authentication handler in auth.go:

  1. Handshake Reception – connector.connect calls readHandshakePacket to parse the initial handshake, extracting the server scramble data, server capabilities, and the initial authentication plugin name (which may be empty).

  2. Defaulting – If the server handshake omits a plugin name, the driver substitutes defaultAuthPlugin = "mysql_native_password" (as defined in const.go).

  3. First Authentication Response – The driver calls mc.auth(authData, plugin), which executes the switch-case logic (lines 279‑389) to build the appropriate authentication response based on the selected plugin.

  4. Server-Initiated Plugin Switch – After the first response, the server may send an Auth Switch Request packet. The driver reads this in handleAuthResult (readAuthResult). If a new plugin name is present, the driver repeats step 3 with the new plugin. Only a single switch is permitted; a second request triggers ErrMalformPkt.

  5. Caching-SHA2 Fast Path – When using caching_sha2_password, the server response determines the next action (handled in handleAuthResult lines 386‑452):

    • 0 bytes – Authentication already succeeded.
    • 1 byte = 2 (cachingSha2PasswordFastAuthSuccess) – The driver validates the OK packet and completes authentication.
    • 1 byte = 3 (cachingSha2PasswordPerformFullAuthentication) – The driver must perform full authentication via clear-text over TLS or RSA-encrypted password.
  6. RSA Public-Key Handling – For RSA-encrypted authentication flows (caching_sha2_password or sha256_password), the driver first checks for a key registered via serverPubKey= in the DSN or RegisterServerPubKey. If unavailable, it requests the public key from the server.

  7. Completion – Upon receiving an OK packet, the driver enables optional compression, configures character sets, and returns the ready mysqlConn.

Configuration Flags That Control Authentication

The driver consults DSN parameters inside the auth switch-case to enable restricted authentication methods:

DSN Option Effect
allowOldPasswords=true Enables the mysql_old_password plugin (checked at lines 84‑86 in auth.go).
allowCleartextPasswords=true Enables the mysql_clear_password plugin (checked at lines 96‑99).
allowNativePasswords=true Explicitly enables mysql_native_password support.
tls=... Determines if clear-text password transmission is permitted for sha256_password and caching_sha2_password full authentication.
serverPubKey=name Uses a pre-registered RSA public key from serverPubKeyRegistry (lines 27‑33) via getServerPubKey (line 78).

Practical Implementation Examples

Default Native Password Connection

For most MySQL 5.x servers, the driver automatically selects mysql_native_password using SHA-1 scrambling:

import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
)

func main() {
    dsn := "user:pass@tcp(localhost:3306)/dbname"
    db, err := sql.Open("mysql", dsn)
    if err != nil {
        panic(err)
    }
    defer db.Close()
    // Authenticated using mysql_native_password via scramblePassword
}

The driver reads the handshake in connector.go lines 33‑44, defaults to "mysql_native_password", and sends the SHA-1-scrambled password via scramblePassword (line 310 of auth.go).

MySQL 8+ with Caching_SHA2_Password

When connecting to MySQL 8.0+ with TLS enabled, the driver handles the caching_sha2_password fast path automatically:

dsn := "user:pass@tcp(localhost:3306)/dbname?tls=skip-verify"
db, err := sql.Open("mysql", dsn)
if err != nil {
    panic(err)
}

If the server advertises caching_sha2_password, the driver first attempts scrambleSHA256Password (line 280). Should the server return cachingSha2PasswordPerformFullAuthentication (line 401), it falls back to RSA-encrypted authentication.

RSA Public-Key Registration for Secure Authentication

To avoid requesting the public key from the server during full authentication, register a PEM-encoded RSA key:

import (
    "crypto/x509"
    "encoding/pem"
    "os"

    "github.com/go-sql-driver/mysql"
)

func init() {
    pubKeyPEM, _ := os.ReadFile("mykey.pem")
    block, _ := pem.Decode(pubKeyPEM)
    rsaPub, _ := x509.ParsePKIXPublicKey(block.Bytes)
    mysql.RegisterServerPubKey("mykey", rsaPub.(*rsa.PublicKey))
}

// Usage
dsn := "user:pass@tcp(localhost:3306)/dbname?serverPubKey=mykey"
db, _ := sql.Open("mysql", dsn)

The registered key is stored in serverPubKeyRegistry (lines 27‑33 of auth.go). During RSA-encrypted flows, getServerPubKey (line 78) retrieves this key instead of requesting one from the server.

Enabling Legacy or Clear-Text Authentication

For older MySQL servers or specific authentication requirements:

// For pre-4.1 password hashing
dsn := "user:pass@tcp(localhost:3306)/dbname?allowOldPasswords=true"

// For clear-text transmission (requires TLS recommended)
dsn := "user:pass@tcp(localhost:3306)/dbname?allowCleartextPasswords=true"

With allowCleartextPasswords=true, the driver returns the password as clear-text in the mysql_clear_password case (lines 96‑101 of auth.go).

Key Source Files and Functions

Understanding the authentication architecture requires referencing these specific files:

File Role Key Sections
auth.go Plugin implementation and RSA handling Plugin switch (L 279‑389), handleAuthResult (L 386‑452), RSA helpers (L 69‑78), registry (L 27‑33)
connector.go Handshake orchestration and plugin selection Handshake read/defaulting (L 33‑44), first auth (L 45‑56), retry logic (L 47‑51)
const.go Protocol constants defaultAuthPlugin definition (L 16), clientPluginAuth flag (L 69)

Summary

  • The go-sql-driver/mysql implements six authentication plugins through a centralized switch-case in auth.go lines 279‑389.
  • Authentication negotiation begins with connector.connect reading the handshake, defaulting to mysql_native_password if the server specifies no plugin.
  • The caching_sha2_password plugin uses a two-phase fast path: SHA256 scrambling first, followed by RSA encryption or clear-text only if the server demands full authentication.
  • DSN flags allowOldPasswords, allowCleartextPasswords, and serverPubKey control access to legacy methods and RSA key provisioning.
  • Only one server-initiated plugin switch is permitted per connection; additional switches trigger ErrMalformPkt.

Frequently Asked Questions

How does the driver handle MySQL 8's default caching_sha2_password authentication?

The driver first attempts the fast authentication path using scrambleSHA256Password to send a SHA256-scrambled response. If the server replies with cachingSha2PasswordPerformFullAuthentication (byte value 3), the driver performs full authentication by either sending the password as clear-text over TLS or encrypting it with the server's RSA public key, as implemented in handleAuthResult lines 386‑452.

What happens if the server does not specify an authentication plugin during the handshake?

If the handshake packet omits the plugin name, the driver substitutes the value of defaultAuthPlugin—defined as "mysql_native_password" in const.go line 16. This ensures backward compatibility with older MySQL servers while maintaining the driver's historical default behavior.

When should I use the serverPubKey DSN parameter?

Use serverPubKey=name when connecting to servers using caching_sha2_password or sha256_password without TLS, but where you possess the server's RSA public key in advance. This prevents the driver from requesting the public key over the network, reducing connection latency and preventing potential man-in-the-middle attacks during key exchange.

Is clear-text password transmission safe with this driver?

Clear-text transmission via allowCleartextPasswords=true is only safe when used over an encrypted TLS connection. Without TLS, the driver exposes the password on the network. The driver explicitly checks for mysql_clear_password at lines 96‑99 of auth.go and only enables it when this flag is set, requiring explicit opt-in for security awareness.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →