---
title: "Set up transactional xCluster"
url: "https://docs.yugabyte.com/stable/deploy/multi-dc/async-replication/async-transactional-setup-semi-automatic/"
---

# Set up transactional xCluster

Semi-automatic setup of transactional (active-active single-master) replication between two YB universes

Set up transactional xCluster replication

- [Automatic](/stable/deploy/multi-dc/async-replication/async-transactional-setup-automatic/)
- [Semi-Automatic](/stable/deploy/multi-dc/async-replication/async-transactional-setup-semi-automatic/)
- [Fully Manual](/stable/deploy/multi-dc/async-replication/async-transactional-setup-manual/)

Note

For v2025.2.1 and later, use Automatic mode.

To use semi-automatic transactional xCluster replication, both the Primary and Standby universes must be running v2024.1.2 or later.

Semi-automatic transactional xCluster replication simplifies the operational complexity of managing replication and making DDL changes.

In this mode, xCluster replication operates at the YSQL database granularity. This means you only run xCluster management operations when adding and removing databases from replication, and not when tables in the databases are created or dropped.

In particular, [DDL changes](#making-ddl-changes "DDL changes") don't require the use of yb-admin. This means DDL changes can be made by any database administrator or user with database permissions, and don't require SSH access or intervention by an IT administrator.

## Set up Semi-automatic mode replication

Before setting up xCluster replication, ensure you have reviewed the [Prerequisites](/stable/deploy/multi-dc/async-replication/#prerequisites "Prerequisites") and [Best practices](/stable/deploy/multi-dc/async-replication/#best-practices "Best practices").

DDLs must be paused on the Primary universe during the entire set up process. [#26053](https://github.com/yugabyte/yugabyte-db/issues/26053)

- [![Server Icon](/icons/database.svg) yugabyted](#yugabyted-setup)
- [Manual](#local-setup)

The following assumes you have set up Primary and Standby universes. Refer to [Set up universes](/stable/deploy/multi-dc/async-replication/async-deployment/#set-up-universes "Set up universes").

1. Create a checkpoint on the Primary universe for all the databases that you want to be part of the replication.
   
   ```sh
   ./bin/yugabyted xcluster create_checkpoint \
       --replication_id <replication_id> \
       --databases <comma_separated_database_names>
   ```
   
   The command informs you if any data needs to be copied to the Standby, or only the schema (empty tables and indexes) needs to be created.
   
   For example:
   
   ```output
   +-------------------------------------------------------------------------+
   |                                yugabyted                                |
   +-------------------------------------------------------------------------+
   | Status               : xCluster create checkpoint success.              |
   | Bootstrapping        : Bootstrap is required for database `yugabyte`.   |
   +-------------------------------------------------------------------------+
   For each database which requires bootstrap run the following commands to perform a backup and restore.
   Run on source:
   ./yugabyted backup --cloud_storage_uri <AWS/GCP/local cloud storage uri>  --database <database_name> --base_dir <base_dir of source node>
   Run on target:
   ./yugabyted restore --cloud_storage_uri <AWS/GCP/local cloud storage uri>  --database <database_name> --base_dir <base_dir of target node>
   ```
2. If needed, perform a full copy of the database(s) on the Primary to the Standby using distributed [backup](/stable/reference/configuration/yugabyted/#backup "backup") and [restore](/stable/reference/configuration/yugabyted/#restore "restore").
3. Enable [point-in-time recovery (PITR)](/stable/manage/backup-restore/point-in-time-recovery/enable-pitr/ "point-in-time recovery (PITR)") on the database(s) on both the Primary and Standby universes:
   
   ```sh
   ./bin/yugabyted configure point_in_time_recovery \
       --enable \
       --retention <retention_period> \
       --database <database_name>
   ```
   
   The `retention_period` must be greater than the amount of time you expect the Primary universe to be down before it self recovers or before you perform a failover to the Standby universe.
4. Set up the xCluster replication.
   
   ```sh
   ./bin/yugabyted xcluster set_up \
       --target_address <ip_of_any_target_cluster_node> \
       --replication_id <replication_id> \
       --bootstrap_done
   ```
   
   You should see output similar to the following:
   
   ```output
   +-----------------------------------------------+
   |                   yugabyted                   |
   +-----------------------------------------------+
   | Status        : xCluster set-up successful.   |
   +-----------------------------------------------+
   ```

The following assumes you have set up Primary and Standby universes. Refer to [Set up universes](/stable/deploy/multi-dc/async-replication/async-deployment/#set-up-universes "Set up universes").

1. Create a checkpoint using the `create_xcluster_checkpoint` command, providing a name for the replication group, and the names of the databases to replicate as a comma-separated list.
   
   ```sh
   ./bin/yb-admin \
       --master_addresses <primary_master_addresses> \
       create_xcluster_checkpoint <replication_group_id> <comma_separated_namespace_names>
   ```
   
   The command informs you if any data needs to be copied to the Standby, or only the schema (empty tables and indexes) needs to be created. For example:
   
   ```output
   Waiting for checkpointing of database(s) to complete
   Checkpointing of yugabyte completed. Bootstrap is not required for setting up xCluster replication
   Successfully checkpointed databases for xCluster replication group repl_group1
   Create equivalent YSQL objects (schemas, tables, indexes, ...) for databases [yugabyte] on the standby universe
   Once the above step(s) complete run 'setup_xcluster_replication'
   ```
   
   You can also manually check the status as follows:
   
   ```sh
   ./bin/yb-admin \
   --master_addresses 127.0.0.1:7100,127.0.0.2:7100,127.0.0.3:7100 \
   is_xcluster_bootstrap_required repl_group1 yugabyte
   ```
   
   You should see output similar to the following:
   
   ```output
   Waiting for checkpointing of database(s) to complete
   Checkpointing of yugabyte completed. Bootstrap is not required for setting up xCluster replication
   ```
2. If needed, perform a full copy of the database on the Primary to the Standby using distributed backup and restore. See [Distributed snapshots for YSQL](/stable/manage/backup-restore/snapshot-ysql/#move-a-snapshot-to-external-storage "Distributed snapshots for YSQL"). Otherwise, create the necessary schema objects (tables and indexes) on the Standby.
3. Enable [point-in-time recovery (PITR)](/stable/manage/backup-restore/point-in-time-recovery/enable-pitr/ "point-in-time recovery (PITR)") on the database(s) on both the Primary and Standby universes:
   
   ```sh
   ./bin/yb-admin \
       --master_addresses <standby_master_addresses> \
       create_snapshot_schedule 1 10 ysql.yugabyte
   ```
4. Set up the xCluster replication group.
   
   ```sh
   ./bin/yb-admin \
   --master_addresses <primary_master_addresses> \
   setup_xcluster_replication <replication_group_id> <standby_master_addresses>
   ```
   
   You should see output similar to the following:
   
   ```output
   xCluster Replication group repl_group1 setup successfully
   ```

## Monitor replication

For information on monitoring xCluster replication, refer to [Monitor xCluster](/stable/launch-and-manage/monitor-and-alert/xcluster-monitor/ "Monitor xCluster").

## Add a database to a replication group

The database should have at least one table in order to be added to replication. If it is a colocated database then there should be at least one colocated table in the database in order for it to be added to replication.

- [![Server Icon](/icons/database.svg) yugabyted](#yugabyted-add-db)
- [Manual](#local-add-db)

<!--THE END-->

1. Create a checkpoint on the Primary universe for all the databases that you want to add to an existing replication group.
   
   ```sh
   ./bin/yugabyted xcluster add_to_checkpoint \
       --replication_id <replication_id> \
       --databases <comma_separated_database_names>
   ```
   
   You should see output similar to the following:
   
   ```output
   Waiting for checkpointing of database to complete
   Successfully checkpointed database db2 for xCluster replication group repl_group1
   Bootstrap is not required for adding database to xCluster replication
   Create equivalent YSQL objects (schemas, tables, indexes, ...) for the database in the standby universe
   ```
2. If bootstrapping is required, perform a full copy of the database(s) on the Primary to the Standby using distributed [backup](/stable/reference/configuration/yugabyted/#backup "backup") and [restore](/stable/reference/configuration/yugabyted/#restore "restore"). If your source database is not empty or you are using automatic mode, it must be bootstrapped.
3. Enable [point-in-time recovery (PITR)](/stable/manage/backup-restore/point-in-time-recovery/enable-pitr/ "point-in-time recovery (PITR)") on the database(s) on both the Primary and Standby universes:
   
   ```sh
   ./bin/yugabyted configure point_in_time_recovery \
       --enable \
       --retention <retention_period> \
       --database <database_name>
   ```
   
   The `retention_period` must be greater than the amount of time you expect the Primary universe to be down before it self recovers or before you perform a failover to the Standby universe.
4. Add the databases to the xCluster replication.
   
   ```sh
   ./bin/yugabyted xcluster add_to_replication \
       --databases <comma_separated_database_names> \
       --replication_id <replication_id> \
       --target_address <IP-of-any-target-node> \
       --bootstrap_done
   ```

<!--THE END-->

1. Create a checkpoint.
   
   ```sh
   ./bin/yb-admin \
   --master_addresses <primary_master_addresses> \
   add_namespace_to_xcluster_checkpoint <replication_group_id> <namespace_name>
   ```
   
   You should see output similar to the following:
   
   ```output
   Waiting for checkpointing of database to complete
   Successfully checkpointed database db2 for xCluster replication group repl_group1
   Bootstrap is not required for adding database to xCluster replication
   Create equivalent YSQL objects (schemas, tables, indexes, ...) for the database in the standby universe
   ```
2. If bootstrapping is required, perform a full copy of the database(s) on the Primary to the Standby using distributed [backup](/stable/reference/configuration/yugabyted/#backup "backup") and [restore](/stable/reference/configuration/yugabyted/#restore "restore"). If your source database is not empty or you are using automatic mode, it must be bootstrapped.
3. Enable [point-in-time recovery (PITR)](/stable/manage/backup-restore/point-in-time-recovery/enable-pitr/ "point-in-time recovery (PITR)") on the database(s) on both the Primary and Standby universes:
   
   ```sh
   ./bin/yb-admin \
       --master_addresses <standby_master_addresses> \
       create_snapshot_schedule 1 10 ysql.yugabyte
   ```
4. Set up the database using the checkpoint.
   
   ```sh
   ./bin/yb-admin \
   --master_addresses <primary_master_addresses> \
   add_namespace_to_xcluster_replication <replication_group_id> <namespace_name> <standby_master_addresses>
   ```
   
   You should see output similar to the following:
   
   ```output
   Successfully added db2 to xCluster Replication group repl_group1
   ```

## Remove a database from a replication group

- [![Server Icon](/icons/database.svg) yugabyted](#yugabyted-remove-db)
- [Manual](#local-remove-db)

To remove a database from a replication group, use the following command:

```sh
./bin/yugabyted xcluster remove_database_from_replication \
    --databases <comma_separated_database_names> \
    --replication_id <replication_id> \
    --target_address <ip_of_any_target_cluster_node>
```

```sh
./bin/yb-admin \
-master_addresses <primary_master_addresses> \
remove_namespace_from_xcluster_replication <replication_group_id> <namespace_name> <standby_master_addresses>
```

You should see output similar to the following:

```output
Successfully removed db2 from xCluster Replication group repl_group1
```

## Drop xCluster replication group

- [![Server Icon](/icons/database.svg) yugabyted](#yugabyted-drop)
- [Manual](#local-drop)

To drop a replication group, use the following command:

```sh
./bin/yugabyted xcluster delete_replication \
    --replication_id <replication_id> \
    --target_address <ip_of_any_target_cluster_node>
```

To drop a replication group, use the following command:

```sh
./bin/yb-admin \
-master_addresses <primary_master_addresses> \
drop_xcluster_replication <replication_group_id> <standby_master_addresses>
```

You should see output similar to the following:

```output
Outbound xCluster Replication group rg1 deleted successfully
```

## Making DDL changes

When performing any DDL operation on databases using semi-automatic transactional xCluster replication (such as creating, altering, or dropping tables, indexes, or partitions), do the following:

1. Execute the DDL on Primary.
2. Execute the DDL on Standby.

The xCluster configuration is updated automatically. You can insert data into the table as soon as it is created on Primary.

When new tables are created with CREATE TABLE, CREATE INDEX, or CREATE TABLE PARTITION OF on the Primary universe, new streams are automatically created. Because this happens alongside the DDL, the new tables are checkpointed at the start of the WAL.

When the same DDL is run on the Standby, the stream info is automatically fetched from the Primary and the table is added to replication using the pre-created stream.

Similarly on table drop, after both sides drop the table, the streams are automatically removed.

When making DDL changes, keep in mind the following:

- DDLs have to be executed on the Standby universe in the same order in which they were executed on the Primary universe.
- When executing multiple schema changes for a given table, each DDL has to be run on both universes before the next DDL/schema change can be performed.
