Adding a replica to a large MySQL 8.4 server usually means a full backup, a copy to the new host, a restore, and a manual gtid_purged step before replication can start. The clone plugin replaces that with one SQL statement on the new server. CLONE INSTANCE pulls a consistent physical snapshot of InnoDB data from a running donor, restarts the recipient, and applies the donor's GTID set, so SOURCE_AUTO_POSITION = 1 starts replication at the right point. It also fails in specific ways. The recipient returns ERROR 3707 when no supervisor restarts mysqld, refuses a donor that is missing from clone_valid_donor_list, and receives MyISAM tables empty. Its own data is gone before the copy starts. This guide covers the setup, the limits, and a runbook from an empty host to a running replica.
- Install the plugin (
mysql_clone.so) on both servers. The donor user needsBACKUP_ADMIN, the recipient user needsCLONE_ADMIN, and the donor must be listed inclone_valid_donor_liston the recipient. - Donor and recipient must run the same release series (for example 8.4.0 and 8.4.11) on the same operating system and platform, with matching
innodb_page_size,innodb_data_file_path, character set, and active plugins. - Only InnoDB data is cloned. Configuration, binary logs, and relay logs are not, and MyISAM and CSV tables arrive empty.
- A remote clone removes the recipient's existing data first, then restarts it through systemd or
mysqld_safe. Without a supervisor you getERROR 3707and startmysqldyourself. - With
gtid_mode=ONon the recipient, the donor's GTID set is applied for you, soCHANGE REPLICATION SOURCE TO ... SOURCE_AUTO_POSITION = 1needs nogtid_purgedstep.
Scope and review date: November 2026. This post covers the clone plugin in MySQL 8.4 LTS on Linux, with notes on Group Replication and MySQL Shell's AdminAPI for InnoDB Cluster and InnoDB ReplicaSet. Statements, variables, and defaults were checked against the MySQL 8.4 Reference Manual and the MySQL Shell 8.4 manual on 9 November 2026. They were not run in a lab, so rehearse them on staging before you clone onto a production host.
What does the MySQL clone plugin copy, and what does it leave behind?
The clone plugin takes a physical snapshot of InnoDB: user tablespaces, the system tablespace, redo, and undo. "User-created data, dictionary metadata, and other system data are cloned," says the failure handling page. The copy also carries the donor's binary log position and gtid_executed set. A local clone (CLONE LOCAL DATA DIRECTORY) copies the instance into a new directory on the same host. A remote clone (CLONE INSTANCE FROM) runs on the recipient and pulls from a donor; that is the mode that provisions replicas.
The clone plugin limitations list what does not travel: server configuration (the recipient keeps its own my.cnf and persisted variables), binary logs, relay logs, and other storage engines. "MyISAM and CSV tables stored in any schema including the sys schema are cloned as empty tables."
-- On the donor: find tables that would arrive empty
SELECT TABLE_SCHEMA, TABLE_NAME, ENGINE
FROM information_schema.TABLES
WHERE ENGINE <> 'InnoDB'
AND TABLE_TYPE = 'BASE TABLE'
AND TABLE_SCHEMA NOT IN ('mysql', 'information_schema',
'performance_schema', 'sys');Interpretation: every row is a table the recipient receives without data. Convert application tables to InnoDB before the clone, or copy them separately with a logical dump. The CSV-based log tables in the mysql schema arrive empty too, which rarely matters on a new replica.
Provisioning a replica with the clone plugin
Follow the numbers: the copy, the restart, then replication from the cloned GTID set
Between steps 1 and 4: the source must keep every binary log written after the snapshot. If they are purged before the replica connects, replication fails at the handshake and you clone again.
Accounts and grants live in InnoDB tables in the mysql schema, and system data is cloned. After a remote clone, log in to the recipient with credentials that exist on the donor, not with the clone user you created on the recipient.
What must match between the donor and the recipient?
The remote cloning prerequisites are checked when CLONE INSTANCE runs, and a mismatch stops the statement before any data is removed. These are the checks that matter most:
| Check | Requirement in MySQL 8.4 |
|---|---|
| Release series | Same series, for example 8.4.0 and 8.4.11; 8.0 to 8.4 is not possible |
| Operating system and platform | Identical, for example Linux 64-bit on both |
innodb_page_size, innodb_data_file_path | Identical, with the same number of system data files of equivalent size |
| Server character set and collation | Identical |
| Active plugins | Every plugin active on the donor, including any keyring plugin, is active on the recipient |
max_allowed_packet | At least 2MB on both servers |
| Undo tablespace file names | Unique on the donor |
| Disk space | Enough for the donor data; with DATA DIRECTORY, enough for both copies |
-- Run on both servers and compare the rows
SELECT @@version, @@version_compile_os, @@version_compile_machine,
@@innodb_page_size, @@innodb_data_file_path,
@@character_set_server, @@collation_server,
@@max_allowed_packet;Interpretation: the first query must match on both servers apart from the patch level. Encrypted or page-compressed data also needs the same file system block size, and encrypted data needs an encrypted connection.
The MySQL Shell clone deployment page adds the history: clone needs 8.0.17 or later, and patch numbers had to match until 8.0.37. The 9.7 manual rules out cloning between 8.4 and 9.7, so clone is not an upgrade path.
Install the plugin and create the clone users
# my.cnf on the donor and the recipient
[mysqld]
plugin-load-add=mysql_clone.so
clone=FORCE_PLUS_PERMANENTInterpretation: per the installation page, FORCE_PLUS_PERMANENT blocks removal at runtime and makes startup fail if the plugin cannot initialize. INSTALL PLUGIN clone SONAME 'mysql_clone.so'; works without a restart.
-- Donor
CREATE USER 'clone_donor'@'10.0.2.%' IDENTIFIED BY '********';
GRANT BACKUP_ADMIN ON *.* TO 'clone_donor'@'10.0.2.%';
-- Recipient
CREATE USER 'clone_admin'@'localhost' IDENTIFIED BY '********';
GRANT CLONE_ADMIN ON *.* TO 'clone_admin'@'localhost';
SET PERSIST clone_valid_donor_list = 'db-02.internal:3306';
-- Both: confirm the plugin is ACTIVE
SELECT PLUGIN_NAME, PLUGIN_STATUS
FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = 'clone';Interpretation: CLONE_ADMIN includes BACKUP_ADMIN and SHUTDOWN, which the recipient needs to replace its data and restart. Setting clone_valid_donor_list needs SYSTEM_VARIABLES_ADMIN, so a different role can own the allow-list. Entries are HOST:PORT, comma-separated, with no spaces and no IPv6 literals.
Does a clone block DDL on the donor in MySQL 8.4?
Not by default. The concurrent DDL page says concurrent DDL is permitted on the donor, controlled by clone_block_ddl, whose default is OFF. The MySQL 8.0 manual dates this behavior to 8.0.27; before that, DDL was blocked on donor and recipient for the whole clone. Whether a concurrent change reaches the clone depends on whether it finishes before the clone takes its dynamic snapshot.
Three statements are blocked whatever the setting: ALTER TABLE ... DISCARD TABLESPACE, ALTER TABLE ... IMPORT TABLESPACE, and ALTER INSTANCE DISABLE INNODB REDO_LOG. On the recipient, CLONE_ADMIN blocks DDL for the duration.
-- Donor: make the clone take an exclusive backup lock instead
SET GLOBAL clone_block_ddl = ON;
-- Donor and recipient: seconds to wait for that lock (default 300)
SELECT @@clone_block_ddl, @@clone_ddl_timeout;Interpretation: with clone_block_ddl = ON, schema migrations on the donor wait until the clone ends, and the clone fails if it cannot get the lock within clone_ddl_timeout. For a replica build, leaving it OFF and pausing scheduled migrations for the clone window is usually simpler.
How do you limit the load a clone puts on the donor?
A remote clone reads every InnoDB page on the donor, so it competes with production I/O. The throttling variables are all dynamic, and the clone system variables page says most of them apply only on the recipient, where CLONE INSTANCE runs.
| Variable | Default | Set on | Effect |
|---|---|---|---|
clone_max_data_bandwidth | 0 (unlimited) | Recipient | Caps the transfer rate in MiB per second; the minimum is 1 MiB per second per thread |
clone_max_concurrency | 16 (range 1 to 128) | Recipient | Maximum threads for a remote clone |
clone_autotune_concurrency | ON | Recipient | Adds threads while throughput improves; never removes them |
clone_enable_compression | OFF | Recipient | Compresses at the network layer, trading CPU for bandwidth |
clone_donor_timeout_after_network_failure | 5 minutes (0 to 30) | Donor | How long the donor keeps the snapshot after a network error |
-- Recipient, before CLONE INSTANCE
SET GLOBAL clone_max_concurrency = 8;
SET GLOBAL clone_max_data_bandwidth = 200; -- MiB per second
SET GLOBAL clone_enable_compression = ON; -- only if the link is the bottleneckInterpretation: MySQL advises a bandwidth limit only when donor disk I/O is saturated. With 8 threads, the floor is 8 MiB per second. If DATA_SPEED in clone_progress stays below the cap while bandwidth is free, disk I/O is the likely bottleneck.
How do you provision a replica with CLONE INSTANCE, step by step?
The recipient is a freshly installed MySQL 8.4 server in the same release series as the donor. The donor can be the source or an existing replica; cloning from a replica keeps the extra read load off the source.
Clone runbook: empty host to running GTID replica
Eight steps; step 5 removes all existing data on the recipient
-
Configure the recipient first
Configuration is not cloned. Set a unique server_id and GTID mode in the recipient's own my.cnf.
[mysqld] server_id=12 gtid_mode=ON enforce_gtid_consistency=ON plugin-load-add=mysql_clone.so -
Prepare the donor
Install the plugin and create a clone user with BACKUP_ADMIN, restricted to the recipient's address.
GRANT BACKUP_ADMIN ON *.* TO 'clone_donor'@'10.0.2.12'; -
Allow the donor on the recipient
Only hosts in clone_valid_donor_list can be cloned from.
SET PERSIST clone_valid_donor_list = 'db-02.internal:3306'; -
Compare the prerequisites
Version series, platform, page size, data file path, character set, plugins, and max_allowed_packet must match.
SELECT @@version, @@innodb_page_size, @@character_set_server; -
Run CLONE INSTANCE on the recipient
Recipient data removedExisting schemas and binary logs on the recipient are dropped before the copy starts.
CLONE INSTANCE FROM 'clone_donor'@'db-02.internal':3306 IDENTIFIED BY '********' REQUIRE SSL; -
Confirm the restart and the result
systemd restarts mysqld. Log in with a donor account and check that STATE is Completed.
SELECT STATE, ERROR_NO, GTID_EXECUTED FROM performance_schema.clone_status; -
Point the replica at the source
GTID auto-positioning starts from the cloned gtid_executed set.
CHANGE REPLICATION SOURCE TO SOURCE_HOST = 'db-01.internal', SOURCE_USER = 'repl', SOURCE_PASSWORD = '****', SOURCE_AUTO_POSITION = 1, SOURCE_SSL = 1; START REPLICA; -
Verify replication, then lock writes
Both threads must report Yes and lag should fall. Then make the replica read-only.
SHOW REPLICA STATUS\G SET PERSIST super_read_only = ON;
Main risk: step 5 is destructive on the recipient. If the copy fails after data removal, the recipient keeps neither its old data nor the new copy, so clone onto a new host or take a backup first.
In step 5, use the donor's real hostname and classic port: the X Protocol port, MySQL Router, and IPv6 literals are not supported. Without an SSL clause, clone tries an encrypted connection and falls back to an unencrypted one; REQUIRE SSL makes it fail instead. Adding DATA DIRECTORY = '/path' keeps the current data and skips the automatic restart.
How do you monitor clone progress and recover from a failed clone?
Two Performance Schema tables describe the current or last clone, on the recipient only, per the monitoring page. clone_status holds one row with the state, the error, and the cloned replication coordinates. clone_progress holds one row per stage, with THREADS, ESTIMATE, DATA, and DATA_SPEED in bytes.
Watching clone_progress on the recipient
Illustrative output, shaped like the real table: the file copy stage is running
Read it as: copied divided by est is the share of the file copy done, and mib_s is the real transfer rate. The numbers are made up; the stage names and columns are from the clone_progress reference.
-- Recipient: overall state and any error
SELECT ID, PID, STATE, ERROR_NO, ERROR_MESSAGE, SOURCE
FROM performance_schema.clone_status;
-- Donor: enable the clone stage events, then read them
UPDATE performance_schema.setup_instruments SET ENABLED = 'YES'
WHERE NAME LIKE 'stage/innodb/clone%';
SELECT EVENT_NAME, WORK_COMPLETED, WORK_ESTIMATED
FROM performance_schema.events_stages_current
WHERE EVENT_NAME LIKE 'stage/innodb/clone%';Interpretation: STATE is Not Started, In Progress, Completed, or Failed. The donor query also needs the stages consumers enabled in setup_consumers. To stop a clone, run KILL QUERY with the PID from clone_status.
The failure handling page describes what each failure leaves:
- Copy fails. The cloned data is rolled back, and the recipient's old data is already gone. Fix the cause and clone again, or restore from a backup.
- Network error. The clone resumes if the link returns within
clone_donor_timeout_after_network_failure; otherwise the donor drops its snapshot. - No supervisor.
ERROR 3707 (HY000): Restart server failed (mysqld is not managed by supervisor process).The data was cloned; startmysqldby hand and checkclone_status.
The RESTART statement page names the supervisors that work: systemd or mysqld_safe on Linux, and the Windows service. A container running mysqld without one will return error 3707.
How do you start GTID replication after the clone?
The cloning for replication page sets the condition. If the recipient runs gtid_mode=ON and the donor runs ON, ON_PERMISSIVE, or OFF_PERMISSIVE, the donor's gtid_executed set is applied on the recipient. With a backup restore you would set gtid_purged yourself; here it is already done.
-- Recipient, after the restart
SELECT @@GLOBAL.gtid_executed;
SELECT BINLOG_FILE, BINLOG_POSITION, GTID_EXECUTED
FROM performance_schema.clone_status;Interpretation: gtid_executed should match the donor's set at snapshot time. BINLOG_FILE and BINLOG_POSITION are the coordinates for replication without GTIDs.
The replication metadata tables (mysql.slave_master_info, mysql.slave_relay_log_info, and mysql.slave_worker_info) are cloned too. If the donor was a replica with auto-positioning channels, those channels resume when you start them. If the donor was the source, create the channel:
CHANGE REPLICATION SOURCE TO
SOURCE_HOST = 'db-01.internal',
SOURCE_PORT = 3306,
SOURCE_USER = 'repl',
SOURCE_PASSWORD = '********',
SOURCE_AUTO_POSITION = 1,
SOURCE_SSL = 1;
START REPLICA;
SHOW REPLICA STATUS\GInterpretation: look for Replica_IO_Running: Yes, Replica_SQL_Running: Yes, and a falling Seconds_Behind_Source. A replication user on caching_sha2_password, the 8.4 default, needs an encrypted connection or GET_SOURCE_PUBLIC_KEY = 1, per the CHANGE REPLICATION SOURCE TO reference.
Binary logs are not cloned. The source must keep every log written since the snapshot until the replica connects, or replication fails with a handshake error. Check binlog_expire_logs_seconds on the source before a long clone.
How do InnoDB Cluster and Group Replication use clone?
Group Replication can use clone for distributed recovery. The cloning for distributed recovery page sets two triggers. Clone is used when the transaction gap exceeds group_replication_clone_threshold, and whenever the needed transactions are no longer in any member's binary logs. The threshold defaults to the maximum GTID sequence number, so by default clone runs only when binary log recovery is impossible.
Install the plugin on every member and grant BACKUP_ADMIN to the recovery user; Group Replication sets clone_valid_donor_list itself. Do not set a low threshold on a busy group: if more transactions than the threshold arrive during the clone, the member clones again after its restart, and can keep doing so.
MySQL Shell's AdminAPI wraps this. dba.createCluster() installs the clone plugin where it is available. addInstance() takes a recoveryMethod of auto (the default), clone, or incremental. Under auto, the AdminAPI clone page compares GTID sets. Identical or Recoverable means incremental recovery is used. Irrecoverable (purged transactions) or Diverged means clone is recommended or required.
// mysqlsh, connected to the cluster; scripts must choose explicitly
var cluster = dba.getCluster()
cluster.addInstance('clusteradmin@db-03.internal:3306', {recoveryMethod: 'clone'})
// InnoDB ReplicaSet takes the same option
var rs = dba.getReplicaSet()
rs.addInstance('rsadmin@db-04.internal:3306', {recoveryMethod: 'clone'})Interpretation: interactive Shell prompts for [C]lone/[I]ncremental recovery/[A]bort; scripts must pass clone or incremental. Clone overwrites the joining instance completely. disableClone: true turns it off for a cluster.
Clone plugin, XtraBackup, or MySQL Shell dump and load?
All three can seed a replica. They differ in what they produce, which versions they cross, and what the recipient goes through.
Three ways to seed a MySQL 8.4 replica
Switch tools to compare the copy type, version rules, and replication setup
Clone plugin
| Question | Clone plugin |
|---|---|
| Copy type | Physical InnoDB snapshot over the MySQL protocol |
| Version rule | Same release series, OS, and platform |
| Storage engines | InnoDB only; MyISAM and CSV arrive empty |
| What it leaves | A running server, no reusable backup |
| Replication position | GTID set applied automatically; binlog position in clone_status |
| Recipient during the copy | Data removed, then an automatic restart |
| Extra software | None beyond the plugin on both servers |
Percona XtraBackup
| Question | Percona XtraBackup |
|---|---|
| Copy type | Physical file copy plus redo, prepared before use |
| Version rule | XtraBackup major version equal to the server's (8.4 for 8.4) |
| Storage engines | InnoDB, MyISAM, and MyRocks |
| What it leaves | A backup directory you can keep and restore again |
| Replication position | xtrabackup_binlog_info; set gtid_purged yourself |
| Recipient during the copy | Stopped for --copy-back or --move-back |
| Extra software | XtraBackup on the donor and the recipient |
Shell dump and load
| Question | MySQL Shell dump and load |
|---|---|
| Copy type | Logical: DDL and rows in chunked files |
| Version rule | Can load into a different MySQL version |
| Storage engines | Rows from any engine |
| What it leaves | Dump files you can keep and load again |
| Replication position | gtidExecuted in @.json; apply with updateGtidSet |
| Recipient during the copy | Running, with local_infile=ON |
| Extra software | MySQL Shell on a client host |
Rule of thumb: clone when donor and recipient run the same series and you only need a replica; use XtraBackup when you also want a backup to keep; use dump and load when versions, platforms, or engines differ.
Percona's version comparison page asks for an XtraBackup version equal to the server's major version, and its GTID replica guide sets gtid_purged by hand: the step clone removes.
// mysqlsh: logical seed of a freshly initialized replica
util.dumpInstance('/backup/db-01-2026-10-28', {threads: 8})
// on the new server, with local_infile = ON
util.loadDump('/backup/db-01-2026-10-28',
{threads: 8, updateGtidSet: 'append', skipBinlog: true})Interpretation: the dump loading utility applies the source GTID set only when you pass updateGtidSet, together with skipBinlog: true. With append, the set must not overlap the target's gtid_executed, so load into a new instance. util.copyInstance() streams the same logical copy without intermediate files.
Frequently asked questions
Can the MySQL clone plugin copy data from MySQL 8.0 to 8.4?
No. The donor and recipient must run the same release series, such as 8.4.0 and 8.4.11, on the same operating system and platform. The MySQL 9.7 manual also rules out cloning between 8.4 and 9.7. To move data across series, upgrade in place, or seed the new server with a logical dump and load and replicate from there.
Does the MySQL clone plugin lock the donor or block writes?
Writes continue on the donor during a clone. In MySQL 8.4, clone_block_ddl defaults to OFF, so DDL is also allowed on the donor, except DISCARD TABLESPACE, IMPORT TABLESPACE, and disabling the redo log. The clone does add read I/O and threads on the donor, which clone_max_data_bandwidth and clone_max_concurrency on the recipient can limit.
Why does CLONE INSTANCE fail with ERROR 3707?
ERROR 3707 means the data was cloned but MySQL could not restart itself, because mysqld is not managed by a supervisor such as systemd or mysqld_safe. It is not a clone failure. Start mysqld manually, then check that performance_schema.clone_status reports Completed before you configure replication.
Is the MySQL clone plugin a backup tool?
Not on its own. A remote clone produces a running copy of the donor, not a backup set you can keep, catalog, or restore to a point in time. A local clone or a clone into a named directory leaves a copy on disk, but there is no retention or verification around it. Keep XtraBackup, MySQL Enterprise Backup, or Shell dumps for backups.
Key takeaways
- Clone needs the plugin on both servers,
BACKUP_ADMINon the donor,CLONE_ADMINon the recipient, and the donor inclone_valid_donor_list. - Match the release series, platform, page size, data file path, character set, and plugins; convert MyISAM tables first, because they arrive empty.
- A remote clone wipes the recipient before copying and needs systemd or
mysqld_safeto restart it; plan forERROR 3707elsewhere. - Throttle from the recipient with
clone_max_data_bandwidthandclone_max_concurrency, and watchclone_progressthere. - With
gtid_mode=ON, start the replica withSOURCE_AUTO_POSITION = 1, and keep the source's binary logs until it connects.
Provision MySQL replicas with JusDB
A clone is quick to start and easy to get wrong on a production donor: a missed MyISAM table, a purged binary log, or a recipient that will not restart. Each of these shows up only after the recipient's old data is gone.
JusDB's MySQL high availability team can review your donor and recipient settings, plan replica or InnoDB Cluster member provisioning with the clone plugin, XtraBackup, or MySQL Shell, and write the runbook for your team to approve and run.