gh-ost is a triggerless online schema migration tool for MySQL. Bytebase invokes gh-ost to migrate MySQL table schemas with minimal downtime.Documentation Index
Fetch the complete documentation index at: https://docs.bytebase.com/llms.txt
Use this file to discover all available pages before exploring further.
How it works
Online schema migration tools operate through a careful orchestration of steps:- Ghost table creation: Creates a new table with the desired schema structure.
- Data migration: Incrementally copies data from the original table to the ghost table while capturing ongoing changes (
INSERT,UPDATE,DELETE). - Table swap: Atomically replaces the original table with the fully synchronized ghost table.
bbdataarchive database, separate from your application schema, to stage gh-ost’s working tables. During the migration two temporary tables exist there:
<table>_<timestamp>_gho— the new table, being built with the desired schema and filled from the original.<table>_<timestamp>_ghc— the changelog table gh-ost uses to track DML against the original during the copy.
RENAME TABLEs:
- The original table moves out of your schema into
bbdataarchiveas~<table>_<timestamp>_del— preserved so you can verify the migration before dropping it (see Step 5). - The
_ghotable moves out ofbbdataarchiveinto your schema, taking the original’s name. It is now your new live table.
_ghc changelog is then dropped — it has no role after cut-over. The _gho is not dropped: it became your new table via the rename. So after a successful migration your application schema contains the new table, and bbdataarchive contains only the renamed _del original.
Requirements and limitations
Requirements
- MySQL version 5.7 or higher
- Row-based logging enabled
- Primary key on the table
- Primary database for migration (replica migration not currently supported)
Limitations
- Foreign key constraints are not supported
- Triggers are not supported
- Large tables may require extended migration time
Performing an online schema migration
Step 1 - Enable online migration
While creating a schema change plan, enable Online migration for the change. To customize gh-ost flags, click Configure next to the toggle. Enabling the toggle prepends a-- gh-ost = { ... } comment to your statement — this is the gh-ost directive that Bytebase parses at execution time to route the migration through gh-ost. With the toggle on and no customization, the statement becomes:
Flags are read once when the issue is created and locked for the run. To change a flag, cancel the task and create a new issue.
Writing the directive manually
For GitOps workflows, or any case where you author SQL outside the Bytebase UI, add the directive yourself on its own line — Bytebase recognizes the same syntax. Use an empty object for default flags:max-load, chunk-size, dml-batch-size, default-retries, cut-over-lock-timeout-seconds, exponential-backoff-max-interval, max-lag-millis, allow-on-master, switch-to-rbr, assume-rbr, heartbeat-interval-millis, nice-ratio, throttle-control-replicas, attempt-instant-ddl, assume-master-host. See the gh-ost command-line reference for what each flag does.
Step 2 - Confirm gh-ost ran
Roll out the resulting issue like any other DDL. Bytebase does not show a separate “gh-ost” badge on the rollout, so confirm the directive was picked up by checking the task log:- A standard MySQL DDL shows four sections — Transaction, Command Execute, Transaction, Database Sync.
- A gh-ost migration shows a single Database Sync section. Command Execute is absent.
Step 3 - Watch progress in the backend logs
The Bytebase UI shows only the start and end of a gh-ost migration. The full picture — cut-over events, the lock-and-rename duration, temporary-table cleanup, and any errors — lands in the Bytebase server log. Tail it and filter forsource=ghost/.
For example, a migration of testdb.tmysql0 logs:
| What’s happening | Log line |
|---|---|
Migration starts on testdb.tmysql0 | Migrating `testdb`.`tmysql0` |
| Atomic cut-over — original and ghost tables are renamed | Tables renamed |
| Writes against the original table were blocked for ~995 ms | Lock & rename duration: 994.696418ms. During this time, queries on `tmysql0` were blocked |
| Bytebase drops the temporary changelog table | Dropping table `bbdataarchive`.`~tmysql0_1778162448_ghc` |
| Migration is done | Done migrating `testdb`.`tmysql0` |
In the raw log, gh-ost’s printf-style messages pass through Bytebase’s structured logger as-is, so you’ll see
%s placeholders alongside the values — for example, msg="Lock & rename duration: %s..." !BADKEY=994.696418ms. The values shown above are spliced in for readability.Step 4 - Cancel if needed
A running gh-ost task can be canceled from the rollout page. Bytebase signals gh-ost to abort and drops the temporary_gho and _ghc tables from bbdataarchive. The original table in your application schema is left untouched.
Step 5 - Post-migration cleanup
gh-ost leaves the renamed_del original in bbdataarchive so you can verify the new table is correct before discarding it, and so a heavy DROP TABLE doesn’t compete with traffic on the freshly cut-over table for I/O. Bytebase doesn’t expose gh-ost’s --ok-to-drop-table flag, so the drop is manual:
- Verify your data integrity and application functionality against the new table.
- Open the
bbdataarchivedatabase from the instance’s database list — Bytebase syncs it like any other schema, so the~yourtablename_{timestamp}_deltable is browseable and queryable. - Once verified, drop
bbdataarchive.~yourtablename_{timestamp}_del.

