go-sql-driver/mysql · error
mysql: unsupported isolation level: %v
Error message
mysql: unsupported isolation level: %v
What it means
Thrown by mapIsolationLevel (utils.go:803) when a transaction's isolation level is not one of the four MySQL supports: ReadUncommitted, ReadCommitted, RepeatableRead, Serializable. MySQL has no equivalent for levels like Snapshot or Linearizable, so the driver cannot map them and rejects the begin.
Source
Thrown at utils.go:803
return nil, errors.New("mysql: driver does not support the use of Named Parameters")
}
dargs[n] = param.Value
}
return dargs, nil
}
func mapIsolationLevel(level driver.IsolationLevel) (string, error) {
switch sql.IsolationLevel(level) {
case sql.LevelRepeatableRead:
return "REPEATABLE READ", nil
case sql.LevelReadCommitted:
return "READ COMMITTED", nil
case sql.LevelReadUncommitted:
return "READ UNCOMMITTED", nil
case sql.LevelSerializable:
return "SERIALIZABLE", nil
default:
return "", fmt.Errorf("mysql: unsupported isolation level: %v", level)
}
}
View on GitHub (pinned to c426bd9379)
Solutions
- Use one of: sql.LevelReadUncommitted, sql.LevelReadCommitted, sql.LevelRepeatableRead, sql.LevelSerializable, or leave Isolation unset (LevelDefault).
- If you need snapshot-style behavior, use REPEATABLE READ (MySQL's default for InnoDB) or START TRANSACTION WITH CONSISTENT SNAPSHOT via raw exec.
- Review your ORM's transaction options mapping to ensure it only requests MySQL-supported levels.
Example fix
// before
tx, err := db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelSnapshot})
// after
tx, err := db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelRepeatableRead}) Defensive patterns
Strategy: validation
Validate before calling
// whitelist isolation levels MySQL supports before BeginTx
var mysqlIsolation = map[sql.IsolationLevel]bool{
sql.LevelReadUncommitted: true,
sql.LevelReadCommitted: true,
sql.LevelRepeatableRead: true,
sql.LevelSerializable: true,
}
func beginTxSafe(db *sql.DB, ctx context.Context, iso sql.IsolationLevel) (*sql.Tx, error) {
opts := &sql.TxOptions{}
if iso != sql.LevelDefault {
if !mysqlIsolation[iso] {
return nil, fmt.Errorf("isolation %v not supported by mysql", iso)
}
opts.Isolation = iso
}
return db.BeginTx(ctx, opts)
} Type guard
// isMySQLIsolationLevel narrows to the levels the driver accepts
func isMySQLIsolationLevel(l sql.IsolationLevel) bool {
switch l {
case sql.LevelDefault, sql.LevelReadUncommitted, sql.LevelReadCommitted,
sql.LevelRepeatableRead, sql.LevelSerializable:
return true
}
return false
} Prevention
- Restrict TxOptions.Isolation to the four MySQL-supported levels or LevelDefault.
- When porting from another DB, audit transaction options for unsupported levels like Snapshot.
- Centralize BeginTx behind a helper that validates the isolation level.
When it happens
Trigger: Calling db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelSnapshot}) (or any non-default, non-MySQL-supported level). Because LevelDefault is handled implicitly by MySQL, only the four named levels plus the default are accepted.
Common situations: Porting code from PostgreSQL/SQL Server that used LevelSnapshot or LevelLinearizable; an ORM defaulting to an isolation level MySQL doesn't have; copy-paste of TxOptions from another DB's example.
Related errors
- mysql: driver does not support the use of Named Parameters
- reader '%s' is <nil>
- reader '%s' is not registered
- argument count mismatch (got: %d; has: %d)
- cannot convert type: %T
AI-assisted analysis of go-sql-driver/mysql@c426bd9379 (2026-08-04).
Data as JSON: /data/errors/eb1195f79e0b815d.json.
Report an issue: GitHub.