ERROR 1036 (HY000): Table '<table_name>' is read only is raised when MySQL receives a write operation (INSERT, UPDATE, DELETE, REPLACE, TRUNCATE, or DDL) against a table that cannot be modified. The error symbol is ER_OPEN_AS_READONLY.
Impact
Any statement that attempts to modify data or structure in the affected table is immediately rejected with this error. The statement does not execute, and if it is part of a larger transaction, the transaction is left in an open state — the application must roll it back or commit the preceding work before proceeding. No data is changed.
Developers typically encounter this in three situations: running write queries against a read replica, using a table that was placed in a read-only InnoDB tablespace, or when the underlying .ibd / .MYD / .MYI files on disk lack write permissions for the MySQL process user. ORMs surface this as a generic database exception — for example, Django raises django.db.utils.OperationalError, SQLAlchemy raises sqlalchemy.exc.OperationalError, and Hibernate raises javax.persistence.PersistenceException — each wrapping the original MySQL error message.
Common Causes
Query sent to a read replica. In a primary/replica setup the replica runs with
read_only=ONorsuper_read_only=ON. Any write from an application connection (not the replication thread) is rejected with 1036. This is the most common production cause.Global or session
read_onlyvariable is set. The server or session hasread_only=ON. Users without theSUPERprivilege (orCONNECTION_ADMINin MySQL 8.0+) cannot write even to tables they own.super_read_only=ONis active. Even SUPER users are blocked. This mode is used on replicas managed by Group Replication or MySQL InnoDB Cluster to prevent accidental writes.InnoDB tablespace opened in read-only mode. The server was started with
--innodb-read-only=1, placing every InnoDB table in a globally read-only state. This is sometimes used for point-in-time analysis of a backup.File system permissions. The
.ibdfile (InnoDB) or.MYD/.MYIfiles (MyISAM) are owned by a different user or are set to read-only on disk, so themysqlOS process cannot write to them.MyISAM table marked crashed or locked. A corrupted or improperly closed MyISAM table may be opened in read-only mode by the storage engine until it is repaired.
Troubleshooting and Resolution Steps
Check read-only variables on the current server:
SHOW VARIABLES LIKE 'read_only'; SHOW VARIABLES LIKE 'super_read_only'; SHOW VARIABLES LIKE 'innodb_read_only';If
read_onlyisONand you are on a replica, this is expected behavior — route write traffic to the primary. If you are on the primary andread_onlyis unexpectedlyON, disable it (requires SUPER or SYSTEM_VARIABLES_ADMIN):SET GLOBAL read_only = OFF; -- Also clear super_read_only if set: SET GLOBAL super_read_only = OFF;Identify whether the current server is a replica:
-- MySQL 8.0.22+ SHOW REPLICA STATUS\G -- MySQL 5.7 / 8.0 before 8.0.22 SHOW SLAVE STATUS\GIf
Replica_IO_Running(orSlave_IO_Running) isYes, the server is a replica. Configure your application's connection string or database driver to route writes to the primary host.Check whether
innodb_read_onlyis active:SHOW VARIABLES LIKE 'innodb_read_only';If
ON, the server was started with--innodb-read-only. Restart MySQL without that flag to allow writes.Inspect file system permissions for the affected table (run as root or the OS user that owns the MySQL data directory):
ls -la /var/lib/mysql/<database_name>/<table_name>.ibd # For MyISAM: ls -la /var/lib/mysql/<database_name>/<table_name>.MYD ls -la /var/lib/mysql/<database_name>/<table_name>.MYIRestore ownership and permissions so the
mysqluser can write:chown mysql:mysql /var/lib/mysql/<database_name>/<table_name>.ibd chmod 660 /var/lib/mysql/<database_name>/<table_name>.ibdRepair a crashed MyISAM table that was opened read-only by the engine:
REPAIR TABLE <table_name>; -- Or from the shell: -- myisamchk --recover /var/lib/mysql/<database_name>/<table_name>Verify the user's privileges are not somehow restricted (though 1036 is a server-level or file-level restriction, not a privilege issue — that would be error 1142):
SHOW GRANTS FOR CURRENT_USER();
Additional Information
- Related error codes: Error 1142 (
ER_TABLEACCESS_DENIED_ERROR) is raised when a user lacks theINSERT/UPDATE/DELETEprivilege — distinct from 1036, which is a server-state or file-system issue. Error 1290 (ER_OPTION_PREVENTS_STATEMENT) is raised when--read-onlyis passed as a command-line option and a write is attempted by a non-SUPER user. - MySQL 8.0 privilege change: In MySQL 8.0, the
SUPERprivilege was split into fine-grained dynamic privileges. To disableread_onlyon 8.0+ you needSYSTEM_VARIABLES_ADMINorSUPER. TheCONNECTION_ADMINprivilege is required to connect whensuper_read_only=ON. - Cloud-managed MySQL (RDS, Cloud SQL, Aurora): Managed replicas enforce
read_onlyandsuper_read_onlyautomatically. You cannot disable them on replica instances; use the primary endpoint for writes, or promote the replica. - Group Replication / InnoDB Cluster: Secondary nodes always run with
super_read_only=ON. Only the primary node accepts writes, and this is managed automatically by the cluster.
Frequently Asked Questions
Why am I getting error 1036 only in production but not in development? Production environments commonly use a primary/replica architecture where application reads are load-balanced across replicas. If your application's connection pool is routing write queries to a replica, you will only see 1036 in production. Audit your database DSN configuration and ensure write operations use the primary/writer endpoint.
Can a user with SUPER privilege bypass read_only?
Yes — on MySQL 5.7 and earlier, a SUPER user can write to tables even when read_only=ON. However, super_read_only=ON blocks even SUPER users. In MySQL 8.0+, SYSTEM_VARIABLES_ADMIN or CONNECTION_ADMIN is needed instead of SUPER.
Does error 1036 roll back an open transaction automatically?
No. MySQL raises the error and rejects the offending statement, but the transaction remains open. Your application must explicitly issue ROLLBACK (or COMMIT if the prior work should be saved) to close the transaction.
Can an individual table be made read-only without making the whole server read-only?
MySQL does not natively support per-table read-only flags via SQL (unlike PostgreSQL's ALTER TABLE ... ENABLE ROW LEVEL SECURITY patterns). You can approximate it by revoking INSERT, UPDATE, DELETE, and ALTER privileges on a specific table, which produces error 1142 rather than 1036. Some storage-engine-level file permission tricks can produce 1036 per table, but this is fragile and not recommended in production.