go-sql-driver/mysql · critical

strict mode has been removed. See…

Error message

strict mode has been removed. See https://github.com/go-sql-driver/mysql/wiki/strict-mode

What it means

This is a hard PANIC (not a returned error) raised during DSN parsing (dsn.go:638) when the connection string contains the 'strict' parameter. The 'strict' DSN option was removed in go-sql-driver/mysql v1.0 (2016) because its behavior is better achieved with collation and parseTime settings. Because sql.Open parses the DSN lazily, this panic typically crashes the process on the first real connection attempt unless recovered.

Solutions

  1. Remove the 'strict=true' (or 'strict=...') parameter from the DSN entirely.
  2. If you relied on strict's error-on-truncate behavior, set sql_mode=STRICT_TRANS_TABLES (or STRICT_ALL_TABLES) on the server / via the DSN 'sql_mode' param instead.
  3. If you relied on strict's time parsing, add parseTime=true and, if needed, loc=... to the DSN.
  4. After removing, run sql.Open then db.Ping() in a test to confirm no panic.

Example fix

// before
sql.Open("mysql", "user:pass@tcp(127.0.0.1:3306)/db?strict=true")

// after
sql.Open("mysql", "user:pass@tcp(127.0.0.1:3306)/db?parseTime=true&sql_mode=STRICT_TRANS_TABLES")
Defensive patterns

Strategy: validation

Validate before calling

// Validate the DSN before handing it to sql.Open.
func hasRemovedStrictParam(dsn string) bool {
    for _, param := range strings.Split(strings.SplitN(dsn, "?", 2)[1], "&") {
        if strings.HasPrefix(param, "strict=") {
            return true
        }
    }
    return false
}

if hasRemovedStrictParam(dsn) {
    log.Fatal("DSN uses removed 'strict' param; remove it and use sql_mode/parseTime instead")
}

Type guard

func dsnIsStrictFree(dsn string) bool {
    q := strings.SplitN(dsn, "?", 2)
    if len(q) < 2 { return true }
    for _, p := range strings.Split(q[1], "&") {
        if strings.HasPrefix(p, "strict=") { return false }
    }
    return true
}

Try / catch

// parseDSN panics, so recover if you handle untrusted DSNs.
defer func() {
    if r := recover(); r != nil {
        if s, ok := r.(string); ok && strings.Contains(s, "strict mode has been removed") {
            // strip the strict param and retry, or surface a clear config error
        } else {
            panic(r) // re-raise unrelated panics
        }
    }
}()
db, err := sql.Open("mysql", dsn)

Prevention

When it happens

Trigger: Passing a DSN containing 'strict=true' (or strict=anything) to sql.Open("mysql", ...). The DSN switch in parseDSNParams hits case "strict" and calls panic(). Since sql.Open itself does not parse params eagerly, the panic fires on first use (Ping/Query) when database/sql builds the connector.

Common situations: Upgrading an old codebase from go-sql-driver v0.x to v1.x without removing the legacy 'strict' DSN option; copy-pasting a DSN from an old tutorial; CI working locally with strict removed but a deployed config still carrying it; vendoring an old example.

Related errors


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

Appendix: source

Thrown at dsn.go:638

		// Reject read-only connections
		case "rejectReadOnly":
			var isBool bool
			cfg.RejectReadOnly, isBool = readBool(value)
			if !isBool {
				return errors.New("invalid bool value: " + value)
			}

		// Server public key
		case "serverPubKey":
			name, err := url.QueryUnescape(value)
			if err != nil {
				return fmt.Errorf("invalid value for server pub key name: %v", err)
			}
			cfg.ServerPubKey = name

		// Strict mode
		case "strict":
			panic("strict mode has been removed. See https://github.com/go-sql-driver/mysql/wiki/strict-mode")

		// Dial Timeout
		case "timeout":
			cfg.Timeout, err = time.ParseDuration(value)
			if err != nil {
				return
			}

		// TLS-Encryption
		case "tls":
			boolValue, isBool := readBool(value)
			if isBool {
				if boolValue {
					cfg.TLSConfig = "true"
				} else {
					cfg.TLSConfig = "false"
				}
			} else if vl := strings.ToLower(value); vl == "skip-verify" || vl == "preferred" {

View on GitHub (pinned to 03d76c7e07)