{"record":{"id":"d2af9c63e0ad54e0","repo":"vitessio/vitess","slug":"no-read-only-variable-in-mysql","errorCode":null,"errorMessage":"no read_only variable in mysql","messagePattern":"no read_only variable in mysql","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/mysqlctl/replication.go","lineNumber":822,"sourceCode":"\n\tfinalRes := make(map[string]string, len(qr.Rows))\n\tfor _, row := range qr.Rows {\n\t\tif len(row) != 2 {\n\t\t\treturn nil, vterrors.New(vtrpcpb.Code_INTERNAL, \"incorrect number of fields in the row\")\n\t\t}\n\t\tfinalRes[row[0].ToString()] = row[1].ToString()\n\t}\n\treturn finalRes, nil\n}\n\n// IsReadOnly return true if the instance is read only\nfunc (mysqld *Mysqld) IsReadOnly(ctx context.Context) (bool, error) {\n\tqr, err := mysqld.FetchSuperQuery(ctx, \"SHOW VARIABLES LIKE 'read_only'\")\n\tif err != nil {\n\t\treturn true, err\n\t}\n\tif len(qr.Rows) != 1 {\n\t\treturn true, errors.New(\"no read_only variable in mysql\")\n\t}\n\tif qr.Rows[0][1].ToString() == \"ON\" {\n\t\treturn true, nil\n\t}\n\treturn false, nil\n}\n\n// IsSuperReadOnly return true if the instance is super read only\nfunc (mysqld *Mysqld) IsSuperReadOnly(ctx context.Context) (bool, error) {\n\tqr, err := mysqld.FetchSuperQuery(ctx, \"SELECT @@global.super_read_only\")\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tif len(qr.Rows) == 1 {\n\t\tsro := qr.Rows[0][0].ToString()\n\t\tif sro == \"1\" || sro == \"ON\" {\n\t\t\treturn true, nil","sourceCodeStart":804,"sourceCodeEnd":840,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/mysqlctl/replication.go#L804-L840","documentation":"IsReadOnly runs \"SHOW VARIABLES LIKE 'read_only'\" via FetchSuperQuery and requires exactly one row. If no row comes back, mysqld is unreachable or the variable is missing, and this error is returned (with true as the conservative read-only answer). It signals the server state could not be determined, not that the server is genuinely read-only.","triggerScenarios":"Calling Mysqld.IsReadOnly when SHOW VARIABLES LIKE 'read_only' returns len(qr.Rows) != 1 — usually because mysqld is down or the DBA connection cannot be established, so the expected single row is missing.","commonSituations":"Tablet health checks during mysqld restart/maintenance windows; super-user connection failures (FetchSuperQuery needs sufficient privileges); nonstandard MySQL builds lacking the read_only variable.","solutions":["Check mysqld process status and connectivity before calling IsReadOnly.","Confirm the DBA/super-user credentials used by FetchSuperQuery are valid — auth failures often surface as missing rows.","Treat the returned bool=true plus this error as 'unknown', and retry or fall back to process-level checks rather than assuming read-only state.","If truly running a server without read_only, upgrade to a standard MySQL build."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"readOnly, err := mysqld.IsReadOnly(ctx)\nif err != nil {\n    if strings.Contains(err.Error(), \"no read_only variable\") {\n        // server unreachable: treat as unknown, bounded retry\n        return retryOrFallback(err)\n    }\n    return vterrors.Wrapf(err, \"checking read_only\")\n}","preventionTips":["Gate IsReadOnly calls on prior health-check success (mysqld reachable).","Use properly privileged DBA credentials so SHOW VARIABLES via super query always returns rows.","Never treat (true, err) as 'definitely read-only' — the bool is conservative when the error is present."],"tags":["mysql","read-only","mysqlctl","connection"],"backgroundTag":"mysql-server-unreachable","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}