go-sql-driver/mysql · error

mysql: unsupported isolation level

Error message

mysql: unsupported isolation level: %v

What it means

Raised by mapIsolationLevel (utils.go:803) when beginning a transaction. MySQL only supports four isolation levels (READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE); any other driver.IsolationLevel passed to sql.TxOptions falls through to this error. Called from mysqlConn.BeginTx (connection.go:623) before issuing 'SET TRANSACTION ISOLATION LEVEL'.

Solutions

  1. Use one of the supported levels: sql.LevelReadUncommitted, sql.LevelReadCommitted, sql.LevelRepeatableRead, or sql.LevelSerializable.
  2. Pass sql.LevelDefault (0) to BeginTx to use the server's default isolation (REPEATABLE READ).
  3. If you need Linearizable semantics, enforce it at the application/serialization layer, not via the MySQL driver.
  4. Audit ORM/framework transaction config to ensure it doesn't inject an unsupported level.

Example fix

// before: unsupported level
tx, err := db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelLinearizable})

// after: use a MySQL-supported level (or default)
tx, err := db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelSerializable})
// or simply
tx, err := db.BeginTx(ctx, nil)
Defensive patterns

Strategy: validation

Validate before calling

func supportedByMySQL(level sql.IsolationLevel) bool {
    switch level {
    case sql.LevelReadUncommitted, sql.LevelReadCommitted,
        sql.LevelRepeatableRead, sql.LevelSerializable, sql.LevelDefault:
        return true
    }
    return false
}

// before BeginTx:
if !supportedByMySQL(opts.Isolation) {
    opts.Isolation = sql.LevelDefault // or pick a supported level
}

Type guard

func isMySQLIsolationLevel(l driver.IsolationLevel) bool {
    switch sql.IsolationLevel(l) {
    case sql.LevelReadUncommitted, sql.LevelReadCommitted,
        sql.LevelRepeatableRead, sql.LevelSerializable, sql.LevelDefault:
        return true
    }
    return false
}

Try / catch

tx, err := db.BeginTx(ctx, opts)
if err != nil && strings.Contains(err.Error(), "unsupported isolation level") {
    opts.Isolation = sql.LevelDefault
    tx, err = db.BeginTx(ctx, opts)
}

Prevention

When it happens

Trigger: Calling db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelLinearizable}) (or LevelSnapshot, or any non-default level other than the four supported ones). The error surfaces directly from BeginTx as the transaction's returned error. Note: LevelDefault is intentionally skipped before mapping, so it does not trigger this.

Common situations: Code ported from PostgreSQL (which supports Snapshot/Serializable-based Linearizable semantics), use of sql.LevelLinearizable (common with spanner-like APIs or test fixtures), generic transaction helpers that pass through arbitrary Isolation levels, or an ORM defaulting to an unsupported level.

Related errors


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

Appendix: 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 03d76c7e07)