MY.L1.DROP_COLUMN — Dropping a column on MySQL commits itself
- Category: safety
- Level: 1
- Confidence: deterministic
- Downtime class: derived per statement — see below
- Stability: stable
- Suites: lint
- Applies to: MySQL 8.4
DROP COLUMN deletes the column and every value in it. down() can add the column back; it cannot
bring back what was in it.
On MySQL there is no transaction either
ALTER TABLE … DROP COLUMN is DDL, so it causes an implicit commit. The values are gone the
instant the statement runs, whatever fails afterwards in the same migration.
PostgreSQL only marks the column dropped — no rewrite, the space returns later. MySQL has no such state, which is why the two engines get their own rule and their own sentence.
The downtime class is conditional, and that is deliberate
This rule never names a class. It comes from the online-DDL matrix, where drop_column is INSTANT
with lock: none — but only while none of four conditions applies:
| condition | what it does |
|---|---|
| a functional index covers the column | takes the drop off its instant path |
| the table is out of instant row-version budget | the statement is refused outright, not downgraded |
ROW_FORMAT=COMPRESSED | forces a rebuild |
the table carries a FULLTEXT index | forces a rebuild |
A run that decided nothing about the live table cannot see which of those holds, so the class
resolves to undetermined rather than to the cheap case. Reporting instant from a static read
would be a promise the server has not made — and one of those four does not merely make the
statement slower, it makes the server reject it.
Not transferable to MariaDB
This rule reasons about MySQL 8.4 semantics — specifically that DDL causes an implicit commit there. MariaDB shares Laravel's driver key and the wire protocol, not those semantics, so the same sentence applied to it would be confident, specific and about another product. SQLens refuses that connection rather than guessing.
Flagged
$table->dropColumn('legacy_ref');
Preferred
// Stop writing and reading the column in a shipped release first, then drop it
// later behind #[SqlensAllowDestructive]. On MySQL the drop is DDL, so it commits
// itself the moment it runs - there is no transaction to take it back.
What the rule does not claim
It does not know whether anything still reads the column — that lives in your application, not in the migration. It says the deletion is irreversible, and that on this engine the surrounding transaction will not save you.
Sources
- MySQL 8.4 — online DDL operations — the conditions under which dropping a column is INSTANT, and the row-version limit that makes the server refuse the statement rather than fall back
- MySQL 8.4 — statements causing an implicit commit
The fix material this rule carries
A finding from this rule carries machine-readable fix material, using this sequence:
deploy_window_drop— Drop across two deploy windows so a rollback in between still finds what it needs.
The payload is material for you or an agent to apply. SQLens writes no migration and runs no DDL. See the remediation payload for every field, the placeholder semantics, and the version rules a consumer has to follow.