go-sql-driver/mysql · warning
key ' ' is reserved
Error message
key '%s' is reserved
What it means
RegisterTLSConfig rejects key names that collide with the DSN 'tls=' shorthand: bool-parseable values (true/false/1/0) and the literals 'skip-verify' and 'preferred' (case-insensitive). These names are reserved so the DSN parser can distinguish them from custom configs.
Solutions
- Pick a non-reserved name for your TLS config, e.g. 'custom', 'prod-tls', or 'rds'.
- If you wanted the reserved behavior, use the literal directly in the DSN (?tls=true / skip-verify / preferred) instead of registering a config.
- Update the DSN's tls= parameter to match the new non-reserved name.
Example fix
// before
mysql.RegisterTLSConfig("skip-verify", tlsCfg) // -> reserved
// after
mysql.RegisterTLSConfig("custom", tlsCfg)
sql.Open("mysql", "user@tcp(host:3306)/db?tls=custom") Defensive patterns
Strategy: validation
Validate before calling
// Reject reserved TLS config names before registering.
func notReservedName(name string) bool {
if _, isBool := readBool(name); isBool { return false }
switch strings.ToLower(name) {
case "skip-verify", "preferred": return false
}
return true
} Type guard
null
Try / catch
// RegisterTLSConfig returns the error directly.
if err := mysql.RegisterTLSConfig(name, tlsCfg); err != nil {
if strings.Contains(err.Error(), "is reserved") {
name = "custom" // pick a non-reserved name
}
} Prevention
- Avoid bool-like and skip-verify/preferred names for custom TLS configs.
- Use the DSN literals for built-in TLS behaviors instead of registering.
- Guard registration against reserved names in a helper.
When it happens
Trigger: Calling mysql.RegisterTLSConfig("skip-verify", cfg), RegisterTLSConfig("preferred", cfg), or RegisterTLSConfig("true"/"false"/"1"/"0", cfg).
Common situations: Choosing a config name that happens to be one of the reserved literals; auto-generating a name that lands on a reserved value.
Related errors
- invalid value for server pub key name
- invalid value for TLS config name
- invalid connectionAttributes value
- invalid dbname
- invalid timeTruncate value
AI-assisted analysis of go-sql-driver/mysql@03d76c7e07 (2026-08-07).
Data as JSON: /api/errors/9e0bf3227af15961.
Report an issue: GitHub.
Appendix: source
Thrown at utils.go:59
// log.Fatal(err)
// }
// if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
// log.Fatal("Failed to append PEM.")
// }
// clientCert := make([]tls.Certificate, 0, 1)
// certs, err := tls.LoadX509KeyPair("/path/client-cert.pem", "/path/client-key.pem")
// if err != nil {
// log.Fatal(err)
// }
// clientCert = append(clientCert, certs)
// mysql.RegisterTLSConfig("custom", &tls.Config{
// RootCAs: rootCertPool,
// Certificates: clientCert,
// })
// db, err := sql.Open("mysql", "user@tcp(localhost:3306)/test?tls=custom")
func RegisterTLSConfig(key string, config *tls.Config) error {
if _, isBool := readBool(key); isBool || strings.ToLower(key) == "skip-verify" || strings.ToLower(key) == "preferred" {
return fmt.Errorf("key '%s' is reserved", key)
}
tlsConfigLock.Lock()
if tlsConfigRegistry == nil {
tlsConfigRegistry = make(map[string]*tls.Config)
}
tlsConfigRegistry[key] = config
tlsConfigLock.Unlock()
return nil
}
// DeregisterTLSConfig removes the tls.Config associated with key.
func DeregisterTLSConfig(key string) {
tlsConfigLock.Lock()
if tlsConfigRegistry != nil {
delete(tlsConfigRegistry, key)
}View on GitHub (pinned to 03d76c7e07)