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

> Explore supported MySQL authentication methods in go-sql-driver/mysql including caching_sha2_password and mysql_native_password. Learn about server negotiation and handshake protocols.

- Repository: [Go SQL Drivers/mysql](https://github.com/go-sql-driver/mysql)
- Tags: deep-dive
- Published: 2026-03-02

---

**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`](https://github.com/go-sql-driver/mysql/blob/main/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`](https://github.com/go-sql-driver/mysql/blob/main/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`](https://github.com/go-sql-driver/mysql/blob/main/connector.go)** and the authentication handler in **[`auth.go`](https://github.com/go-sql-driver/mysql/blob/main/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`](https://github.com/go-sql-driver/mysql/blob/main/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`](https://github.com/go-sql-driver/mysql/blob/main/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:

```go
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`](https://github.com/go-sql-driver/mysql/blob/main/connector.go) lines 33‑44, defaults to `"mysql_native_password"`, and sends the SHA-1-scrambled password via `scramblePassword` (line 310 of [`auth.go`](https://github.com/go-sql-driver/mysql/blob/main/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:

```go
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:

```go
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`](https://github.com/go-sql-driver/mysql/blob/main/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:

```go
// 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`](https://github.com/go-sql-driver/mysql/blob/main/auth.go)).*

## Key Source Files and Functions

Understanding the authentication architecture requires referencing these specific files:

| File | Role | Key Sections |
|------|------|--------------|
| **[`auth.go`](https://github.com/go-sql-driver/mysql/blob/main/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`](https://github.com/go-sql-driver/mysql/blob/main/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`](https://github.com/go-sql-driver/mysql/blob/main/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`](https://github.com/go-sql-driver/mysql/blob/main/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`](https://github.com/go-sql-driver/mysql/blob/main/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`](https://github.com/go-sql-driver/mysql/blob/main/auth.go) and only enables it when this flag is set, requiring explicit opt-in for security awareness.