MySQL DROP COLUMN: syntax and safety
ALTER TABLE t DROP COLUMN c. MySQL has no IF EXISTS for columns, and dropping a column silently drops indexes that used it.
Quick answer
The COLUMN keyword is optional (DROP middle_name works), but include it. DROP on its own is ambiguous to read and easy to confuse with dropping an index.
Dropping multiple columns
One statement, one pass over the table:
Do this rather than issuing separate ALTER TABLE statements. Each ALTER can rebuild the table, so two statements can mean two rebuilds. Combining them is one operation.
You can mix operations in the same statement:
There is no IF EXISTS
This is the first thing people try, and it does not work:
MySQL supports IF EXISTS for DROP TABLE and DROP INDEX, but not for DROP COLUMN. PostgreSQL does, and MariaDB does, which is why the expectation is so common. MySQL does not.
Dropping a column that is not there gives:
For an idempotent migration, check the catalog first:
Then branch in your migration tool. Inside a stored procedure you can build the statement conditionally:
That is verbose enough that most people let their migration tool handle it, which is the right instinct.
Dropping a column drops indexes that used it
This is the side effect worth knowing about, because nothing warns you.
Given a table with two indexes:
Two things happened:
idx_bis gone entirely. It indexed onlyb, so droppingbdestroyed it.idx_bcsurvived, but is now an index on(c)alone. Its leading column was removed.
That second one is the dangerous one. The index still exists and still has its old name, so a casual SHOW INDEX looks fine. But an index on (b, c) and an index on (c) answer completely different questions. Queries that relied on the composite are now doing something else, and you will find out through a slow query rather than an error.
After dropping a column, review any composite index that included it.
If a column is the only column of a UNIQUE constraint, that constraint disappears with it, silently removing a data-integrity guarantee.
Foreign keys block the drop
Drop the constraint first, then the column:
Note DROP FOREIGN KEY takes the constraint name, not the column name. Find it with:
Names like child_ibfk_1 are auto-generated and are not stable across environments. Do not hard-code them in a migration that has to run somewhere else.
You cannot drop every column
A table must have at least one column. The error tells you exactly what to do.
ALGORITHM=INSTANT
Since MySQL 8.0.29, InnoDB can drop a column instantly, without rebuilding the table:
On a large table this is the difference between milliseconds and hours. It works by marking the column as dropped in metadata rather than rewriting every row.
Specifying ALGORITHM=INSTANT explicitly is worth doing even though MySQL will often pick it anyway, because if the operation cannot be instant, you get an error instead of an unexpected multi-hour table rebuild on production:
That is a much better outcome than discovering it during the maintenance window, and the Reason: tells you which part of your statement was the problem.
Caveats worth knowing:
- Instant drops leave the old data in place. Row size does not shrink until the table is rebuilt, so you reclaim no space.
- There is a limit on how many instant column changes a table can accumulate before a rebuild is forced.
- It is InnoDB-only.
The other algorithms:
| Algorithm | Behaviour |
|---|---|
INSTANT | Metadata only. Fastest. Reclaims no space. |
INPLACE | Rebuilds within the table, usually allows concurrent DML. |
COPY | Copies to a new table, blocks writes. Slowest. |
Dropping a column is not reversible
There is no undo. The data is gone, and on a large table restoring it means a full restore or a rebuild from backup.
Two habits worth having.
Stop using the column before you drop it. Deploy code that no longer reads or writes it, let it run long enough to be sure, then drop. A column dropped while something still selects it produces ERROR 1054: Unknown column, and that error will come from whichever service you forgot about.
Consider renaming first. Renaming is instant and reversible:
Anything still referencing it breaks immediately and loudly, in a way you can undo in seconds. Drop it for real once a full deploy cycle has passed.
RENAME COLUMN needs MySQL 8.0. On 5.7 you need CHANGE COLUMN with the full type definition repeated, which is its own hazard: get the type wrong and you have silently altered the column.
Common problems
ERROR 1091: Can't DROP 'x'. The column does not exist, or you spelled it differently. Column names are case-insensitive on most platforms but the check is against the real name.
ERROR 1064 near IF EXISTS. MySQL has no IF EXISTS for columns. Check information_schema instead.
ERROR 1828: needed in a foreign key constraint. Drop the constraint first.
ERROR 1090: You can't delete all columns. Use DROP TABLE.
ERROR 1054: Unknown column after a deploy. Something still references the dropped column. This is the one that causes outages, and it is why you stop using a column before dropping it.
The ALTER is taking hours. It is rebuilding the table. Cancel it, add ALGORITHM=INSTANT, and see whether it is eligible. If not, use an online schema change tool such as pt-online-schema-change or gh-ost.
Quick reference
| Task | Syntax |
|---|---|
| Drop a column | ALTER TABLE t DROP COLUMN c; |
| Drop several | ALTER TABLE t DROP COLUMN a, DROP COLUMN b; |
| Drop instantly (8.0.29+) | ALTER TABLE t DROP COLUMN c, ALGORITHM=INSTANT; |
| Conditional drop | Check information_schema.COLUMNS first. No IF EXISTS. |
| Drop a foreign key first | ALTER TABLE t DROP FOREIGN KEY fk_name; |
| Find the constraint name | information_schema.KEY_COLUMN_USAGE |
| Safer than dropping | ALTER TABLE t RENAME COLUMN c TO c_deprecated; |
| Drop the whole table | DROP TABLE t; |