go-sql-driver/mysql · critical
no pem data found, data: %s
Error message
no pem data found, data: %s
What it means
Thrown in the caching_sha2_password full-auth path (auth.go:432) after the server's public-key response IS received (it passed the iAuthMoreData check) but pem.Decode could not parse a PEM block from it. The %s shows the leftover bytes that pem.Decode could not consume — indicating the payload is not a valid PEM-encoded RSA public key.
Source
Thrown at auth.go:432
}
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 err
}
}
return mc.resultUnchanged().readResultOK()
default:
return ErrMalformPktView on GitHub (pinned to c426bd9379)
Solutions
- Enable TLS (tls=true) or use a unix socket to avoid the public-key exchange entirely.
- Inspect the %s bytes in the error — if they look like an error message, the server is rejecting auth for another reason (fix the underlying auth issue).
- Bypass proxies/routers; connect directly to MySQL to rule out payload mangling.
- If you can pin the server key, register it as the DSN server public key to skip the exchange.
Example fix
// before: caching_sha2_password over plain TCP
// dsn := "user:pass@tcp(host:3306)/db"
// after: TLS avoids requesting/parsing the server public key
dsn := "user:pass@tcp(host:3306)/db?tls=skip-verify"
db, err := sql.Open("mysql", dsn) Defensive patterns
Strategy: validation
Validate before calling
// prefer TLS/unix so the server key is never requested/parsed
func safeDSN(user, pass, host, db string) string {
return fmt.Sprintf("%s:%s@tcp(%s)/%s?tls=true", user, pass, host, db)
} Try / catch
if err := db.PingContext(ctx); err != nil {
if strings.Contains(err.Error(), "no pem data found") {
// server's key payload was unparseable; switch to TLS/unix and retry
}
} Prevention
- Use TLS or a unix socket with caching_sha2_password to skip public-key exchange.
- Keep proxies/routers out of the auth path; they commonly mangle auth-more-data packets.
- Pin the server public key in the DSN when TLS is unavailable.
When it happens
Trigger: Connecting with caching_sha2_password over plain TCP without TLS, where the server DID respond to the public-key request but the payload is not PEM-encoded PKIX RSA key data — corrupted bytes, a proxy rewriting the response, or a non-conforming server.
Common situations: A proxy/router that mangles the auth-more-data packet; packet corruption on a flaky link; a MySQL fork that sends the key in a non-PEM format; a man-in-the-middle injecting garbage. The trailing %s in the message is the diagnostic clue.
Related errors
- no Pem data found, data: %s
- unexpected resp from server for caching_sha2_password, perfo
- 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/8ce7bd4b42da2193.json.
Report an issue: GitHub.