Destination Checks
Checks on the destination tables' existence, storage engine, key and structure, the schema compatibility rules, and destination triggers.
Skipped for purge jobs, which copy nothing.
DEST_TABLE_EXISTENCE_CHECK
Every job table must exist in the destination schema, under the same name, as a base table.
Fix: create the destination tables from the source’s table definitions. If the destination’s lookup tables will be empty, see disable_foreign_key_checks .
DEST_STORAGE_ENGINE_CHECK
Every destination job table must be InnoDB: the copy writes each batch in one destination transaction, and only InnoDB rolls it back. A table whose engine is reported as NULL is refused as <table>(<unknown>).
Fix: ALTER TABLE <table> ENGINE=InnoDB; on the destination.
DEST_KEY_IDENTITY_CHECK
The destination PRIMARY KEY must have the source’s columns, in key order, with the same type, charset and collation: a different collation changes which keys collide and the order in which verification reads rows. One widening is allowed: a utf8mb3 key column copied into utf8mb4 with the twin collation, such as utf8mb3_general_ci to utf8mb4_general_ci.
Fix: give the destination table the source’s primary key.
DEST_SCHEMA_COMPATIBILITY_CHECK
Matches source and destination columns by name, ignoring letter case, then compares each pair. The destination may be looser than the source, never stricter. The copy inserts an explicit value for every column and never relies on destination defaults or indexes, so a relaxation is harmless, while an extra constraint would reject rows. Every incompatible table is reported, each with its first fatal difference.
Allowed: the destination may be looser
| Difference | Why it is safe |
|---|---|
| Secondary indexes dropped | The copy does not read them |
auto_increment, defaults or ON UPDATE dropped | The copy supplies every value |
NOT NULL relaxed to nullable | Strictly more permissive |
| Source column generated, destination plain | The read materialises the value |
Column INVISIBLE on one side only | Every read and INSERT names its columns, so the column is copied and verified |
Integer display width (bigint(20) vs bigint, tinyint(1) vs tinyint, a zerofill width) | Cosmetic: the copy and the hash read the value, not its padded text. unsigned and zerofill themselves must match |
year(4) vs year | Cosmetic |
| Column order differs | Advisory, one per table, naming each displaced column. Every read and INSERT names its columns |
| Column name differs only in letter case | Advisory. The copy names the source’s columns, so rows copy and verify normally |
Fatal: the destination must not be stricter
| Difference | Consequence |
|---|---|
| A column on one side only | Wrong column mapping |
| Column type differs (beyond display width) | Value corruption or insert failure |
Destination NOT NULL, source nullable | NULL rows rejected mid-copy |
| Destination column generated | An explicit value is rejected |
| Destination-only unique index | Rows the source holds as distinct collide, and the copy fails |
| Primary key differs | Reported by DEST_KEY_IDENTITY_CHECK |
CHECK constraints and foreign keys are not compared. A destination-only one that rejects a row fails that batch’s copy, which rolls back before anything is deleted.
Destination unique indexes
Unique indexes are compared by what they make unique, not by name: two unique indexes are equivalent when they have the same set of parts, each (column or expression, prefix length, collation).
- Prefix length counts:
UNIQUE(email(10))rejects addresses thatUNIQUE(email)accepts. - Collation counts: a case-insensitive destination collation collides rows a binary source collation keeps apart. A
utf8mb3column copied into itsutf8mb4twin compares as the source. - Ignored: the index name, the letter case of column names, part order and
DESC. - Functional unique indexes pass only when the expression matches a source one exactly and no column differs in charset or collation.
Fix: drop the destination unique index, or add an equivalent one to the source.
Charset and collation
| Situation | Result |
|---|---|
Charset differs on a non-key column, verification: count or none | Fatal |
Charset differs on a non-key column, verification: sha256 | Warning |
| Collation differs on a column of a destination unique index | Fatal, unless the column is a utf8mb4 twin |
| Collation differs elsewhere outside the key | Warning |
| Charset or collation differs on a key column | DEST_KEY_IDENTITY_CHECK |
| Either side’s character set is not supported | COLUMN_CHARSET_CHECK, earlier |
A charset change can transliterate or truncate text silently. Count verification proves which keys arrived, not their values, so it cannot see that; sha256 can, and fails the batch before anything is deleted.
DEST_INSERT_TRIGGER_VISIBILITY_CHECK
The destination account cannot be proven to see a job table’s triggers. Without TRIGGER on a table, an account sees an empty trigger list, so the list does not mean there are none, and DEST_INSERT_TRIGGER_CHECK could not be trusted. The message names each table with its state.
Fix: grant TRIGGER directly to the account at schema or table scope (Permissions
). A role-held TRIGGER stays unconfirmed. --force-triggers does not apply.
DEST_INSERT_TRIGGER_CHECK
A destination table has an INSERT trigger. It would change copied rows before verification reads them.
Fix: drop the destination INSERT triggers. --force-triggers does not apply.
