usememos/memos · critical
Parse DSN error
Error message
Parse DSN error
What it means
The MySQL driver builds its DSN via mergeDSN(profile.DSN) and then runs go-sql-driver's ParseDSN on the result. If ParseDSN fails, the raw cause is discarded and replaced with a plain "Parse DSN error", so the message gives no detail. Invalid DSN syntax includes bad parameter pairs, invalid net/addr, or unparseable user:pass segments.
Source
Thrown at store/db/mysql/mysql.go:32
type DB struct {
db *sql.DB
profile *profile.Profile
config *mysql.Config
}
func NewDB(profile *profile.Profile) (store.Driver, error) {
// Open MySQL connection with parameter.
// multiStatements=true is required for migration.
// See more in: https://github.com/go-sql-driver/mysql#multistatements
dsn, err := mergeDSN(profile.DSN)
if err != nil {
return nil, err
}
driver := DB{profile: profile}
driver.config, err = mysql.ParseDSN(dsn)
if err != nil {
return nil, errors.New("Parse DSN error")
}
driver.db, err = sql.Open("mysql", dsn)
if err != nil {
return nil, errors.Wrapf(err, "failed to open db: %s", profile.DSN)
}
return &driver, nil
}
func (d *DB) GetDB() *sql.DB {
return d.db
}
func (d *DB) Close() error {
return d.db.Close()
}
View on GitHub (pinned to 14d757ce1f)
Solutions
- Use the canonical format: user:password@tcp(127.0.0.1:3306)/memos?multiStatements=true
- Percent-encode special characters in the password (e.g. @ -> %40, / -> %2F)
- Reproduce locally with mysql.ParseDSN(dsn) to see the underlying error text
- Verify no conflicting duplicate params are introduced by mergeDSN
Example fix
# before MEMOS_DSN="root:p@ss/word@tcp(localhost:3306)/memos" # after MEMOS_DSN="root:p%40ss%2Fword@tcp(localhost:3306)/memos"
Defensive patterns
Strategy: validation
Validate before calling
if _, err := mysql.ParseDSN(dsn); err != nil {
log.Fatalf("invalid MySQL DSN: %v", err) // shows the real cause
} Type guard
func validMySQLDSN(dsn string) bool {
_, err := mysql.ParseDSN(dsn)
return err == nil
} Prevention
- Percent-encode special characters in DSN passwords
- Pre-validate DSNs with go-sql-driver's ParseDSN during config load to get detailed errors
When it happens
Trigger: DSN strings like "user:pass@tcp(host:3306)/db?badParam" (parameter without '='), a missing '/dbname', or an addr without 'tcp(...)' wrapping; also mergeDSN appending conflicting params.
Common situations: Copy-pasting a PostgreSQL-style URL (postgres://...) into the MySQL DSN; special characters in passwords not percent-encoded; trailing spaces or shell-quoting mistakes in the MEMOS_DSN env var.
Related errors
AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15).
Data as JSON: /api/errors/f6fccc242ea4adac.
Report an issue: GitHub.