Skip to main content

Fixed: "ERROR 1238 (HY000): Variable is a read only variable" in MySQL

· 4 min read
Jagdish Kumawat
Founder @ Dewiride

SET innodb_rollback_on_timeout = ON failed with ERROR 1238 (HY000): Variable 'innodb_rollback_on_timeout' is a read only variable. Some settings can only be chosen when the server starts. With Docker Compose, that takes one line and a restart.

What I Was Doing​

A lock wait timeout rolls back only the waiting statement, and I wanted it to roll back the whole transaction. MySQL 9.7.4 in Docker has a setting for that, so I tried it as root:

mysql: root session
SET GLOBAL innodb_rollback_on_timeout = ON;

What I Expected​

Query OK.

What I Got​

Output
ERROR 1238 (HY000): Variable 'innodb_rollback_on_timeout' is a read only variable

SET GLOBAL innodb_rollback_on_timeout = ON failing with ERROR 1238 (HY000): Variable 'innodb_rollback_on_timeout' is a read only variable.

Leaving out GLOBAL gives the same answer, even for an administrator.

What I Checked​

The option's entry. The InnoDB options page lists each option's scope, and whether it's Dynamic. For this one, Dynamic is No: it's a startup option.

Why It Happens​

A variable marked as not dynamic is read once, when the server starts, and then stays as it is for that run. There's no privilege that changes this.

The Fix​

Pass it when MySQL starts. With Docker Compose, add command to the service in compose.yaml:

compose.yaml (excerpt)
services:
mysql:
image: mysql:9.7
command: ["--innodb-rollback-on-timeout=ON"]

Recreate the container. The data stays in its volume:

Terminal
docker compose up -d --wait

After the Fix​

mysql: root session
SELECT @@innodb_rollback_on_timeout;
Output (after the restart)
+------------------------------+
| @@innodb_rollback_on_timeout |
+------------------------------+
| 1 |
+------------------------------+
1 row in set (0.000 sec)

And it does what I wanted. A transaction changes row 4, then times out waiting for row 3:

mysql
START TRANSACTION;
UPDATE products SET QuantityOnHand = 47 WHERE Id = 4;
UPDATE products SET QuantityOnHand = 48 WHERE Id = 3;
SELECT Id, QuantityOnHand FROM products WHERE Id IN (3, 4);
Output (the last two statements)
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

+----+----------------+
| Id | QuantityOnHand |
+----+----------------+
| 3 | 50 |
| 4 | 50 |
+----+----------------+
2 rows in set (0.001 sec)

After the restart, a lock wait timeout on product 3 also undoes the earlier change to product 4: a SELECT shows both at 50.

Row 4 is back at 50: the whole transaction was rolled back.

Common Mistakes​

MistakeWhat happensDo this instead
docker compose restart after editing compose.yamlThe new command isn't applieddocker compose up -d, which recreates it
Looking for a privilege to grantNo privilege helpsSet it at startup
Assuming your app can set itIt's for the whole serverHandle the rollback in your app, if you can't change the server

Troubleshooting​

SymptomLikely causeFix
is a GLOBAL variable and should be set with SET GLOBALA different rule: it has no session formERROR 1229
The container won't start after the changeA wrong option namedocker compose logs mysql names it
The value hasn't changedThe container wasn't recreatedRun docker compose up -d --wait

Conclusion​

ERROR 1238 means the setting can only be chosen at startup. In Docker Compose, that's a command in compose.yaml and docker compose up -d --wait, and your data stays where it is.

Additional Resources​

Stay Updated

Subscribe to our newsletter for the latest tutorials, tech insights, and developer news.

By subscribing, you agree to our privacy policy. Unsubscribe at any time.