go-sql-driver/mysql · error
invalid DSN: did you forget to escape a param value?
Error message
invalid DSN: did you forget to escape a param value?
What it means
Returned by ParseDSN while parsing the [protocol(address)] section: it found an opening '(' but the segment between '(' and the '/' contains a stray ')' that is not the closing terminator (dsn.go:441). The hint asks whether a parameter value was left unescaped because, in practice, an unescaped ')' inside the password is what desynchronizes the parser and leaves a ')' in the address region.
Source
Thrown at dsn.go:29
import (
"bytes"
"context"
"crypto/rsa"
"crypto/tls"
"errors"
"fmt"
"maps"
"math/big"
"net"
"net/url"
"sort"
"strconv"
"strings"
"time"
)
var (
errInvalidDSNUnescaped = errors.New("invalid DSN: did you forget to escape a param value?")
errInvalidDSNAddr = errors.New("invalid DSN: network address not terminated (missing closing brace)")
errInvalidDSNNoSlash = errors.New("invalid DSN: missing the slash separating the database name")
errInvalidDSNUnsafeCollation = errors.New("invalid DSN: interpolateParams can not be used with unsafe collations")
)
// Config is a configuration parsed from a DSN string.
// If a new Config is created instead of being parsed from a DSN string,
// the NewConfig function should be used, which sets default values.
type Config struct {
// non boolean fields
User string // Username
Passwd string // Password (requires User)
Net string // Network (e.g. "tcp", "tcp6", "unix". default: "tcp")
Addr string // Address (default: "127.0.0.1:3306" for "tcp" and "/tmp/mysql.sock" for "unix")
DBName string // Database name
Params map[string]string // Connection parameters
ConnectionAttributes string // Connection Attributes, comma-delimited string of user-defined "key:value" pairsView on GitHub (pinned to c426bd9379)
Solutions
- URL-encode the password (and username) when assembling the DSN: wrap each in url.QueryEscape(...).
- Stop putting the secret in the DSN entirely: build a *mysql.Config, set cfg.User/cfg.Passwd, then open via mysql.NewConnector(cfg) + sql.OpenDB.
- Audit the DSN for any literal '(' or ')' that is not part of the protocol(address) group and escape or remove it.
Example fix
// before
dsn := fmt.Sprintf("%s:%s@tcp(%s)/db", user, pass, addr) // pass has a ')'
// after
dsn := fmt.Sprintf("%s:%s@tcp(%s)/db", url.QueryEscape(user), url.QueryEscape(pass), addr) Defensive patterns
Strategy: validation
Validate before calling
// Escape user/password before building the DSN so ')' cannot desync the parser.
func safeDSN(user, pass, addr, db string) string {
return fmt.Sprintf("%s:%s@tcp(%s)/%s", url.QueryEscape(user), url.QueryEscape(pass), addr, db)
} Try / catch
// errInvalidDSNUnescaped is unexported; match by message substring.
if _, err := mysql.ParseDSN(dsn); err != nil {
if strings.Contains(err.Error(), "forget to escape") {
// re-escape credentials and rebuild the DSN
}
} Prevention
- Never interpolate raw credentials into a DSN with fmt.Sprintf — always url.QueryEscape them.
- Prefer building a *mysql.Config and opening via mysql.NewConnector to avoid string parsing entirely.
- Add a unit test that ParseDSN succeeds for every DSN your config layer can produce.
When it happens
Trigger: Calling ParseDSN or sql.Open('mysql', ...) with a DSN like 'user:p)ss(@tcp(host:3306)/db' where the raw password contains a ')' character before the '(' of the address. The parser, scanning dsn[k+1:i] for the address, sees the stray ')' via strings.ContainsRune and returns errInvalidDSNUnescaped.
Common situations: Passwords generated by a secret manager containing random punctuation; copy-pasting a DSN from a wiki that stripped URL-encoding; building the DSN with fmt.Sprintf and a raw password instead of url.QueryEscape; an OAUTH-style token used as a password.
Related errors
- invalid DSN: missing the slash separating the database name
- default addr for network '{cfg.Net}' unknown
- invalid value / unknown config name: {cfg.TLSConfig}
- invalid value / unknown server pub key name: {cfg.ServerPubK
- invalid bool value: {value}
AI-assisted analysis of go-sql-driver/mysql@c426bd9379 (2026-08-04).
Data as JSON: /data/errors/c3132b0f75cbad61.json.
Report an issue: GitHub.