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 usingscrambleSHA256Password. If the server responds withcachingSha2PasswordPerformFullAuthentication, 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). UsesscramblePasswordwith 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 usingscrambleOldPassword. Only enabled whenAllowOldPasswordsis set totrue.mysql_clear_password– Transmits the password in clear text. Only enabled whenAllowCleartextPasswordsis set totrue.client_ed25519– MariaDB-specific plugin using Ed25519 signatures via theauthEd25519function.
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:
-
Handshake Reception –
connector.connectcallsreadHandshakePacketto parse the initial handshake, extracting the server scramble data, server capabilities, and the initial authentication plugin name (which may be empty). -
Defaulting – If the server handshake omits a plugin name, the driver substitutes
defaultAuthPlugin = "mysql_native_password"(as defined inconst.go). -
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. -
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 triggersErrMalformPkt. -
Caching-SHA2 Fast Path – When using
caching_sha2_password, the server response determines the next action (handled inhandleAuthResultlines 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.
-
RSA Public-Key Handling – For RSA-encrypted authentication flows (
caching_sha2_passwordorsha256_password), the driver first checks for a key registered viaserverPubKey=in the DSN orRegisterServerPubKey. If unavailable, it requests the public key from the server. -
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.golines 279‑389. - Authentication negotiation begins with
connector.connectreading the handshake, defaulting tomysql_native_passwordif the server specifies no plugin. - The
caching_sha2_passwordplugin 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, andserverPubKeycontrol 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →