Skip to main content
Engineering6 min read

Schema changes without downtime on MySQL

Which ALTER TABLE operations are instant, which rebuild the table, and how to sequence a column rename so nothing breaks while both versions of your application are running.

SchemaSync Engineering

Product engineering · NG&NR Technologies

Most schema changes can be applied to a busy MySQL database without taking the application down. The ones that cannot are usually not the ones people expect, and the difference is worth knowing before you write the migration rather than during it.

Three classes of change

MySQL 8.0 offers three algorithms for ALTER TABLE, and the one it picks determines whether your change is free or expensive.

AlgorithmWhat happensTypical cost
INSTANTMetadata-only change; the table is not touchedMilliseconds, whatever the table size
INPLACEThe table is modified without a full copy; usually permits concurrent reads and writesProportional to size, but the table stays available
COPYA full rebuild into a new table; writes are blocked for the durationProportional to size, and the table is effectively read-only

You do not have to guess which one you will get. Ask for the cheap one explicitly, and let MySQL refuse:

SQL
-- Fails immediately if it cannot be done instantly, rather than-- quietly rebuilding a 200 GB table during your deployment window.ALTER TABLE `orders`  ADD COLUMN `channel` varchar(20) NULL,  ALGORITHM = INSTANT;

What is instant, and what is not

  • Instant: adding a nullable column at the end of the table, dropping a column, renaming a column, changing a column's default, adding or removing a virtual generated column.
  • In place: adding or dropping a secondary index, adding a foreign key when checks are off, changing whether an index is visible.
  • Full rebuild: changing a column type, adding a column at a specific position, changing the primary key, changing character set or ROW_FORMAT, converting to a partitioned table.

The practical lesson is that adding a column is nearly free provided you let it go at the end of the table. Insisting on AFTER some_column for tidiness turns a metadata update into a full copy. Column order is not worth an outage.

Renaming a column without breaking anything

The rename itself is instant. The problem is not the database, it is that during a rolling deployment both the old and the new version of your application are running at once, and they disagree about the column's name. A single-step rename breaks one of them.

The way through it is to expand, migrate, then contract — four deployments, none of which has a moment where the running code and the schema disagree:

  1. Add the new column

    Add customer_reference alongside the existing cust_ref. Nothing reads it yet. Instant, and invisible to the application.

  2. Write to both, read from the old

    Deploy code that writes both columns and still reads the old one. Backfill the new column for existing rows in batches.

  3. Read from the new

    Deploy code that reads the new column. Both columns are still being written, so a rollback to the previous version remains safe.

  4. Stop writing the old one, then drop it

    Once no running version references it — and you are confident you will not roll back that far — drop the old column. Instant.

It looks like a lot of ceremony for a rename. It is, and it is still cheaper than an outage. The same shape works for splitting a column, changing a type, or moving a value to another table.

When a rebuild is unavoidable

Sometimes you genuinely need to change a column type on a very large table. Two options remain, and both keep the table available:

  • An online schema change tool such as pt-online-schema-change or gh-ost, which builds a shadow copy, keeps it in sync with triggers or the binary log, and swaps it in at the end.
  • Expand and contract again — add a new column of the new type, dual-write, backfill in batches, switch reads, then drop the original. More application work, but no external tooling and no shadow table.

Rehearse it

Whatever the plan, run it once against a restored backup of production at production scale. That rehearsal tells you the real duration, and it is the only step in this article that cannot be replaced by reading. Generate the script, apply it to a copy, time it, then decide.

  • zero downtime
  • alter table
  • mysql 8
  • online ddl
  • deployment
All articles
Keep reading
  • Engineering24-Jun-26

    Reading a generated migration script before you run it

    Generated SQL is only as safe as the review it gets. A practical checklist for the five minutes before you execute a migration against production.

  • Engineering20-May-26

    Catching schema drift in CI

    A comparison step in your pipeline turns an invisible problem into a red build. What to compare, when to run it, and how to avoid a check nobody trusts.

  • Practices08-Jul-26

    Why database schemas drift, and what to do about it

    Drift is not caused by carelessness. It is the predictable result of several people fixing urgent problems in different places. Here is where it comes from and how to make it visible.

Start comparing in the next five minutes

Download the 14-day trial and run it against your own databases. Full feature set, no credit card, nothing to configure first.

  • Windows 10 and 11 (64-bit)
  • Code-signed installer with a published checksum
  • Email support during the trial