Chapter 06 · Data Modification, Transactions, Isolation, Locks, and Deadlocks
Metadata Locks, Row Locks, Gap/Next-Key Locking, and Online Change Interactions
Diagnose MariaDB metadata, record, gap and next-key locks; connect lock footprint to indexes, isolation, long transactions and online DDL behavior.
Learning outcomes
An “online” ALTER TABLE can still sit waiting for minutes while a quiet application session holds a transaction open. An UPDATE of a range can block inserts into values that do not yet exist. A missing index can turn a logically narrow predicate into a much wider lock footprint because InnoDB locks index records/ranges it scans. These incidents look mysterious only when all locks are treated as one thing.
MariaDB has different lock families for different correctness problems. Metadata locks (MDL) protect object definitions while statements/transactions use them. InnoDB record locks protect index records. Gap locks protect spaces between index records, and next-key locks combine a record with the preceding gap. Their lifetime and scope depend on transaction boundaries, isolation level, indexes and SQL shape. Diagnosis therefore starts by identifying which lock family is blocking progress.
Distinguish metadata locks from InnoDB record, gap and next-key locks.
Explain why InnoDB locks index records/ranges and how predicate/index choice affects lock footprint.
Reproduce a transaction blocking DDL through metadata locking and diagnose it safely.
Use built-in transaction/lock views and optional Performance Schema metadata instrumentation appropriately.
Explain why online DDL reduces some blocking but does not eliminate metadata-lock coordination.
Performance Schema is disabled by default in MariaDB
documentation, so the mandatory diagnosis path uses
SHOW FULL PROCESSLIST,
INFORMATION_SCHEMA.INNODB_TRX,
INNODB_LOCKS/INNODB_LOCK_WAITS or
the sys.innodb_lock_waits view where available.
performance_schema.metadata_locks is excellent
when Performance Schema and metadata instrumentation are
enabled. The metadata_lock_info plugin is
optional and must never be assumed installed.
1. Metadata locks protect definitions until the transaction is done
When a transaction uses a table, MariaDB holds metadata protection so another session cannot change that table definition underneath the active statement/transaction. MariaDB documentation states that metadata locks can last until transaction end, and rolling back to a savepoint does not release them. Therefore a read-only-looking transaction can delay DDL if it touches the target table and remains open.
USE servicehub_tx_lab;START TRANSACTION;SELECT work_order_id,status FROM work_orders WHERE work_order_id=1001;-- Leave the transaction open.
ALTER TABLE work_orders NOWAIT ADD COLUMN mdl_demo INT NULL;
Using NOWAIT makes this a safe lab because Session
B fails immediately instead of waiting for the very large
default metadata lock timeout. Without NOWAIT, the ALTER can
queue until Session A COMMIT/ROLLBACK or
lock_wait_timeout expires. This is a metadata wait,
not an InnoDB row-lock timeout controlled by
innodb_lock_wait_timeout.
ROLLBACK;
2. Diagnose the waiting session before killing anything
When an ALTER is waiting, first identify the waiting statement
and the old transaction that owns the conflicting metadata lock.
SHOW FULL PROCESSLIST can reveal a state such as
waiting for table metadata lock.
INFORMATION_SCHEMA.INNODB_TRX shows active InnoDB
transactions and their start times. A long-running transaction
with no currently busy statement is often more important than
the visibly waiting DDL.
SHOW FULL PROCESSLIST;SELECT trx_id, trx_state, trx_started, trx_mysql_thread_id, trx_rows_locked, trx_rows_modifiedFROM information_schema.innodb_trxORDER BY trx_started;
Do not immediately KILL the oldest connection. Determine the business operation, whether it has uncommitted work, and whether the application can safely retry. Killing a transaction causes rollback work and can create an incident larger than the original DDL wait.
3. Optional metadata-lock instrumentation
On MariaDB 10.5.2 and later,
performance_schema.metadata_locks can list granted
and pending metadata locks when Performance Schema and the
metadata lock instrument are enabled. Performance Schema itself
is documented as disabled by default, so a course lab should not
quietly depend on it. Enable it in a disposable instance or
production only through an explicit observability design.
SHOW VARIABLES LIKE 'performance_schema';-- If it is ON, enable metadata instrumentation at runtime:UPDATE performance_schema.setup_instrumentsSET enabled='YES', timed='YES'WHERE name LIKE 'wait/lock/metadata%';SELECT OBJECT_TYPE,OBJECT_SCHEMA,OBJECT_NAME, LOCK_TYPE,LOCK_DURATION,LOCK_STATUS,OWNER_THREAD_IDFROM performance_schema.metadata_locksWHERE OBJECT_SCHEMA='servicehub_tx_lab';
The alternative metadata_lock_info plugin exposes
INFORMATION_SCHEMA.METADATA_LOCK_INFO, but the
plugin is distributed separately from its installation state.
Keep that path optional and label INSTALL PLUGIN
privileges/security implications rather than changing a
production server just to satisfy a tutorial.
4. Record locks live on indexes, not on an abstract row object
InnoDB’s locking model is index-oriented. A point lookup using a unique index can lock the exact matching index record. A range predicate can lock multiple records and, under REPEATABLE READ, gaps between them so another transaction cannot insert a new row into the protected range. A next-key lock combines a record lock with the gap preceding that record.
| Lock idea | What is protected | Why it matters |
|---|---|---|
| Record lock | An index record. | Conflicting UPDATE/DELETE/locking reads of that indexed record must wait. |
| Gap lock | A gap between index records. | Can block insertion of a new key into a scanned range even though no row existed there. |
| Next-key lock | Record plus preceding gap. | Used for range protection under REPEATABLE READ locking operations. |
| Metadata lock | Object definition/use, not the row payload. | DDL may wait even when no row-level conflict exists. |
Under READ COMMITTED, MariaDB documentation describes gap locking as substantially reduced, with important exceptions such as foreign-key and duplicate-key checks. That can improve concurrency but changes phantom/range protection. Verify target-version behavior before using isolation changes as a tuning shortcut.
5. Indexed predicates change the lock footprint
Suppose a dispatcher locks all queued high-priority work. The
composite index
(status, priority, work_order_id) lets InnoDB
navigate a relatively narrow key range. If that index is removed
and the engine must scan a much broader access path, more index
records/ranges can participate in locking. “Add an index to make
the SELECT faster” is incomplete; for locking DML, access-path
design can change concurrency behavior too.
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;START TRANSACTION;SELECT work_order_id,status,priorityFROM work_ordersWHERE status='open' AND priority BETWEEN 1 AND 2ORDER BY status,priority,work_order_idFOR UPDATE;-- Keep open only long enough to observe another session.
INSERT INTO work_orders(work_order_id,customer_id,technician_id,status,priority,estimated_cost,version_no,opened_at)VALUES (1010,1,NULL,'open',1,50.00,1,NOW());
Whether and exactly where Session B waits depends on the index access path, isolation level and key values. Use EXPLAIN before the locking test and lock instrumentation during it. Do not turn a single observed lock into an eternal claim about every plan/version.
6. Observe row lock waits
For active InnoDB waits, MariaDB exposes transaction and lock
tables such as INNODB_TRX,
INNODB_LOCKS and INNODB_LOCK_WAITS.
MariaDB’s sys.innodb_lock_waits view, available
from 10.6, summarizes waiter/blocker relationships for human
diagnosis. These views are more useful than staring at a blocked
client because they connect the waiting statement to the
transaction holding the lock.
SELECT * FROM sys.innodb_lock_waits\GSELECT trx_id,trx_state,trx_started,trx_mysql_thread_id, trx_requested_lock_id,trx_rows_locked,trx_queryFROM information_schema.innodb_trx\GSELECT * FROM information_schema.innodb_locks\GSELECT * FROM information_schema.innodb_lock_waits\G
Some rows appear only while a wait exists, and privileges can restrict visibility. Lock IDs are diagnostic identifiers whose format is not an application API. Capture them during the incident, but do not store parsing logic that depends on their internal encoding.
7. Online DDL is not “no locks ever”
Modern MariaDB supports many online ALTER TABLE paths and
improved LOCK=NONE behavior, but online DDL still
needs metadata coordination at phases of the operation. A long
transaction can therefore delay the start or completion of an
otherwise online change. Production migration planning needs a
lock budget, transaction-age monitoring, target-version
algorithm verification and a rollback/abort boundary.
Before a large ALTER, inspect long transactions, replica/Galera state, disk headroom and the exact algorithm/lock mode supported by that version. A green staging run with no concurrent long transaction does not prove zero blocking in production.
8. Lab checklist, failure repair and knowledge check
- Open Session A, START TRANSACTION and SELECT from work_orders.
- From Session B, run ALTER TABLE ... NOWAIT and record the metadata-lock failure.
- Use SHOW FULL PROCESSLIST and INNODB_TRX to identify the old transaction.
- If Performance Schema is already enabled in your disposable lab, inspect metadata_locks; otherwise keep this optional.
- Create a row-lock wait with SELECT ... FOR UPDATE and inspect sys.innodb_lock_waits/INNODB_TRX.
- Compare a unique point lock with a range lock; record EXPLAIN access paths.
- ROLLBACK every open lab transaction and clean up any inserted row.
Check your understanding
- Why can a plain SELECT inside a transaction block ALTER TABLE later?
- Which timeout controls metadata-lock waiting versus InnoDB record-lock waiting?
- Why can an index affect lock scope as well as performance?
- What is a next-key lock?
- Why is performance_schema.metadata_locks an optional rather than unconditional course dependency?
Review the answers
Transactions keep metadata locks on objects they use until transaction end, so DDL may queue. Metadata-lock waits use lock_wait_timeout (or statement WAIT/NOWAIT), while InnoDB record-lock waits use innodb_lock_wait_timeout. InnoDB locks index records/ranges, so the chosen access path can widen or narrow the set encountered. A next-key lock combines an index-record lock with the preceding gap. Performance Schema is documented as disabled by default, so its metadata_locks table is available only when the feature/instrumentation is enabled.
Treat long transactions as an operational risk even when they are “idle.” Monitor transaction age, not just query duration. Before DDL, prove that the lock acquisition window is acceptable and have an abort policy; do not rely on the word online as a guarantee of zero waiting.
9. Summary and bridge
Metadata locks protect definitions; InnoDB record/gap/next-key locks protect indexed data and ranges. Transaction lifetime, isolation and access path determine what remains protected and for how long. Diagnosing a wait therefore means identifying lock family, waiting transaction, blocker, SQL, age and safe release action—not simply increasing a timeout.
The final lesson creates the most instructive concurrency failure: a deadlock. You will force two sessions into cyclic lock acquisition, inspect the detected cycle, distinguish it from a timeout, and build a bounded retry strategy that replays the entire transaction safely rather than hiding the symptom.