go-sql-driver/mysql · critical
unexpected resp from server for caching_sha2_password, perfo
Error message
unexpected resp from server for caching_sha2_password, perform full authentication
What it means
Thrown in the caching_sha2_password full-auth path (auth.go:426) when, after the client requests the server's RSA public key, the first byte of the response is not iAuthMoreData (0x01). The client expected the server to send its public key; getting a different leading byte means the protocol state is unexpected — typically the server sent an error or an auth-result packet instead.
Source
Thrown at auth.go:426
pubKey := mc.cfg.pubKey
if pubKey == nil {
// request public key from server
data, err := mc.buf.takeSmallBuffer(4 + 1)
if err != nil {
return err
}
data[4] = cachingSha2PasswordRequestPublicKey
err = mc.writePacket(data)
if err != nil {
return err
}
if data, err = mc.readPacket(); err != nil {
return err
}
if data[0] != iAuthMoreData {
return fmt.Errorf("unexpected resp from server for caching_sha2_password, perform full authentication")
}
// parse public key
block, rest := pem.Decode(data[1:])
if block == nil {
return fmt.Errorf("no pem data found, data: %s", rest)
}
pkix, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return err
}
pubKey = pkix.(*rsa.PublicKey)
}
// send encrypted password
err = mc.sendEncryptedPassword(oldAuthData, pubKey)
if err != nil {
return errView on GitHub (pinned to c426bd9379)
Solutions
- Enable TLS in the DSN (tls=true or a registered tls config) so the driver uses cleartext auth over an encrypted channel instead of requesting a public key.
- Use a unix socket (net=unix) which also takes the cleartext-auth fast path.
- Provide the server RSA public key via the DSN (allowOldPasswords / server pub key registration) to skip the request step.
- Verify the server actually supports caching_sha2_password and the account is not locked/expired; test the same credentials in the mysql CLI.
Example fix
// before: plain TCP, no TLS
// dsn := "user:pass@tcp(host:3306)/db"
// after: enable TLS so full auth uses cleartext over encrypted channel
dsn := "user:pass@tcp(host:3306)/db?tls=true"
db, err := sql.Open("mysql", dsn) Defensive patterns
Strategy: validation
Validate before calling
// build a DSN that avoids the public-key request path
func mysqlDSN(user, pass, host, db string) string {
// tls=true makes caching_sha2_password use cleartext over TLS
return fmt.Sprintf("%s:%s@tcp(%s)/%s?tls=true", user, pass, host, db)
}
// or use net=unix to take the cleartext fast path Try / catch
db, err := sql.Open("mysql", dsn)
if err := db.PingContext(ctx); err != nil {
if strings.Contains(err.Error(), "unexpected resp from server for caching_sha2_password") {
// switch DSN to tls=true / unix socket and retry
}
} Prevention
- Always connect to MySQL 8+ over TLS or a unix socket to avoid the RSA key-exchange path.
- Pre-register the server RSA public key in the DSN if you must run without TLS.
- Verify the account is not locked/expired by testing in the mysql CLI.
When it happens
Trigger: Connecting with caching_sha2_password (MySQL 8 default) over a non-TLS, non-unix-socket connection WITHOUT a preconfigured server public key, where the server's response to the public-key request is not a key blob — e.g. the server replied with an error or terminated auth.
Common situations: MySQL 8+ over plain TCP with no TLS and no allowOldPasswords/serverPubKey configured; an intermediary (proxy, RDS proxy) that rewrites the auth handshake; a server that rejects the account mid-handshake; version/compatibility skew between client and server auth plugins.
Related errors
- no pem data found, data: %s
- no Pem data found, data: %s
- invalid value / unknown config name: {cfg.TLSConfig}
- invalid value / unknown server pub key name: {cfg.ServerPubK
- invalid value for server pub key name: %v
AI-assisted analysis of go-sql-driver/mysql@c426bd9379 (2026-08-04).
Data as JSON: /data/errors/fd4cceb256f1494b.json.
Report an issue: GitHub.