We recently deployed a new environment using MariaDB 12.3, while our older environments were still running MariaDB 10.11.
Soon after deployment, some concurrent UPDATE operations started failing with:
ERROR 1020 (HY000): Record has changed since last read in table
The interesting part: the same application logic had been running fine on MariaDB 10.11.
Finding the Difference
After comparing both environments, we found this:
| Environment | MariaDB | innodb_snapshot_isolation |
|---|---|---|
| Existing | 10.11.x | OFF |
| New | 12.3.x | ON |
You can check it with:
SHOW VARIABLES LIKE 'innodb_snapshot_isolation';
MariaDB changed the default of innodb_snapshot_isolation to ON starting from newer releases.
With it enabled, MariaDB performs stricter write-conflict detection under REPEATABLE READ.
A simplified scenario:
Transaction A reads row
↓
Transaction B updates and commits row
↓
Transaction A tries to update same row
↓
ERROR 1020
So the concurrent access pattern was not necessarily new.
What changed was how MariaDB handled it.
The Compatibility Fix
Our existing production environments were already running successfully with:
innodb_snapshot_isolation = OFF
So for the new environment, we aligned the configuration:
SET GLOBAL innodb_snapshot_isolation = OFF;
After changing it, the ERROR 1020 failures disappeared under our workload.
Is Disabling It Always the Right Solution?
No.
ERROR 1020 can indicate a legitimate concurrency conflict.
Longer term, applications may want to handle this using approaches such as:
transaction retries
SELECT ... FOR UPDATE
atomic UPDATE statements
optimistic locking
shorter transactions
For us, disabling it was mainly a compatibility decision so the upgraded environment behaved consistently with the existing production system.
Takeaway
The main lesson wasn't the one-line config change.
It was this:
When application behavior changes after a database upgrade, compare database defaults and configuration — not just application code.
A major database upgrade can expose concurrency assumptions that have existed unnoticed for years.
In our case, the difference came down to one setting:
MariaDB 10.11 → innodb_snapshot_isolation = OFF
MariaDB 12.3 → innodb_snapshot_isolation = ON
Sometimes a production issue that looks like an application regression is actually a database behavior change.
Top comments (2)
The takeaway about comparing server defaults rather than app code is the one most upgrade postmortems miss. innodb_snapshot_isolation=ON turns a silently-lost-update race into a hard error, which is arguably MariaDB doing you a favour — the conflict was always there on 10.11, it just resolved last-writer-wins without telling anyone.
Worth noting for anyone hitting this: the retry path matters more than the flag. If your UPDATE is idempotent, catching ERROR 1020 and retrying the transaction keeps the safety on. We went the same config-alignment route during a version jump and it worked, but we tracked it as debt precisely because the stricter mode was flagging a real race.
Yeah, that’s a fair point.
For us, disabling
innodb_snapshot_isolationwas mostly about keeping the new environment consistent with the existing 10.11 setup first, rather than treating it as the final fix.But I agree that the stricter behavior is exposing a race that was already there. The retry approach is probably the better long-term direction, especially for operations that are safe to retry.
Good call on treating the config change as debt rather than considering the issue fully solved.