go-sql-driver/mysql · error

invalid dbname

Error message

invalid dbname %q: %w

What it means

Thrown by ParseDSN when the database-name segment of the DSN (the text between the '/' and the first '?') fails percent-decoding via url.PathUnescape. %q is the raw dbname and %w wraps the underlying url error. It means the dbname contains a malformed percent-escape (a '%' not followed by two hex digits).

Solutions

  1. Read the %q value in the error to see the exact raw dbname, then remove or correct the percent-encoding (encode a literal '%' as '%25').
  2. Avoid special characters in the database name, or build the dbname segment with proper URL encoding (e.g. url.PathEscape).
  3. If the name genuinely contains a '%', escape it as %25 in the DSN string.

Example fix

// before
db, err := sql.Open("mysql", "user@tcp(127.0.0.1:3306)/my%db")
// after (literal % encoded as %25)
db, err := sql.Open("mysql", "user@tcp(127.0.0.1:3306)/my%25db")
Defensive patterns

Strategy: validation

Validate before calling

// Validate the dbname portion decodes before opening.
import "net/url"
if _, err := url.PathUnescape(dbname); err != nil {
    return fmt.Errorf("bad dbname encoding: %w", err)
}

Type guard

null

Try / catch

// DSN parse failures surface from sql.Open / ParseDSN; check err immediately.
db, err := sql.Open("mysql", dsn)
if err != nil {
    return fmt.Errorf("invalid DSN: %w", err)
}

Prevention

When it happens

Trigger: Calling sql.Open or mysql.ParseDSN with a DSN whose database segment has a broken percent-escape, e.g. "user@tcp(127.0.0.1:3306)/my%db" or ".../db%GG". url.PathUnescape rejects these because '%d'/'%GG' are not valid hex sequences.

Common situations: Database names containing special characters that a developer tried to percent-encode but mistyped; a literal '%' copied from another source; programmatic DSN assembly that inserts a raw '%' character.

Related errors


AI-assisted analysis of go-sql-driver/mysql@03d76c7e07 (2026-08-07). Data as JSON: /api/errors/6caa65aeb686b798. Report an issue: GitHub.

Appendix: source

Thrown at dsn.go:465

					}
				}
				cfg.Net = dsn[j+1 : k]
			}

			// dbname[?param1=value1&...&paramN=valueN]
			// Find the first '?' in dsn[i+1:]
			for j = i + 1; j < len(dsn); j++ {
				if dsn[j] == '?' {
					if err = parseDSNParams(cfg, dsn[j+1:]); err != nil {
						return
					}
					break
				}
			}

			dbname := dsn[i+1 : j]
			if cfg.DBName, err = url.PathUnescape(dbname); err != nil {
				return nil, fmt.Errorf("invalid dbname %q: %w", dbname, err)
			}

			break
		}
	}

	if !foundSlash && len(dsn) > 0 {
		return nil, errInvalidDSNNoSlash
	}

	if err = cfg.normalize(); err != nil {
		return nil, err
	}
	return
}

// parseDSNParams parses the DSN "query string"
// Values must be url.QueryEscape'ed

View on GitHub (pinned to 03d76c7e07)