Instruction

Oracle 19c PDB Migration Between CDBs (PDB Relocate Method)

Introduction

PDB Relocate migrates a Pluggable Database from one Container Database to another using an online block-level copy. The source PDB remains open in READ WRITE mode during the data copy phase -- sessions continue uninterrupted until the final switchover. After relocation completes, the PDB exists only in the target CDB. The source PDB is automatically removed.

When to use PDB Relocate:

  • Minimal-downtime PDB migration when both CDBs are simultaneously accessible via SQL*Net
  • Consolidating PDBs without scheduling an application outage window for the copy phase
  • Same-version (19c to 19c) migrations between single-instance CDBs

When to use a different method:

Method Use Instead When
Unplug/Plug (ALTER PLUGGABLE DATABASE ... UNPLUG INTO + CREATE PLUGGABLE DATABASE ... USING) The PDB can tolerate full downtime, or both CDBs cannot be simultaneously accessible via SQL*Net
Remote Clone (CREATE PLUGGABLE DATABASE ... FROM pdb@dblink) You want to duplicate a PDB (copy, not move) while keeping the source PDB running
Data Pump Full Transportable (expdp TRANSPORTABLE=ALWAYS FULL=Y) Cross-platform migration with different endianness, or when multitenant operations are blocked by version/platform incompatibility

Scope: This instruction covers same-version (19c to 19c) PDB relocation only. Cross-version relocation (upgrade scenarios) requires additional steps and is out of scope.

Naming Conventions

Placeholder Meaning
{SOURCE_CDB} The CDB that currently contains the PDB
{TARGET_CDB} The CDB that will receive the PDB
{RELOCATE_PDB} The PDB being relocated
{C##REMOTE_CLONE_USER} Common user on the source CDB for the database link (e.g., C##REMOTE_CLONE)
{CLONE_LINK} Database link name on the target CDB (e.g., CLONE_LINK)
{SOURCE_HOST} Hostname or IP of the source CDB server
{TARGET_HOST} Hostname or IP of the target CDB server
{ORACLE_HOME} Oracle home directory (e.g., /u01/app/oracle/product/19.0.0/dbhome_1)
{SOURCE_SYS_PASSWORD} SYS password for the source CDB (DBCA method only)
{TARGET_SYS_PASSWORD} SYS password for the target CDB (DBCA method only)

Replace these with your actual values throughout.

Assumptions

This instruction assumes:

  • Oracle Linux 8 (x86_64) on all servers involved
  • Oracle Database 19c (19.3 or later with any Release Update) on both CDBs
  • Both CDBs are single-instance (not RAC)
  • The reader has SYSDBA administrative privilege on both CDBs
  • The PDB to be relocated ({RELOCATE_PDB}) is currently open and operational in {SOURCE_CDB}
  • Both CDBs run on the same platform and endianness (both x86_64 Linux)
  • The target CDB character set is AL32UTF8 (which accepts PDBs with any character set), or the character sets are compatible
  • The target CDB has the same or a superset of the database options installed in the source CDB
  • The COMPATIBLE initialization parameter on the target CDB is equal to or greater than the source CDB
  • Oracle Managed Files (OMF) is configured on the target CDB (db_create_file_dest is set). A FILE_NAME_CONVERT alternative is noted for non-OMF environments
  • Transparent Data Encryption (TDE) is not in use on the PDB being relocated
  • The reader understands basic Oracle administration (SQL*Plus, environment variables, tnsnames.ora)

Prerequisites

Automatic

Oracle handles these automatically during PDB relocation -- no manual action required:

  • Hot clone data copy: Oracle performs an online block-level copy of the source PDB datafiles, redo, and undo while the source PDB remains open in READ WRITE mode
  • Session draining: Oracle 19c automatically drains active sessions during the switchover phase. Application Continuity failover is invoked for sessions that cannot be drained within the timer window
  • Source PDB removal: After successful relocation, the source PDB is closed and removed (with AVAILABILITY NORMAL). With AVAILABILITY MAX, a tombstone PDB with status RELOCATED remains until manually dropped
  • Service registration: After the PDB opens in the target CDB, Oracle registers the PDB service with the listener
  • Connection redirection: With AVAILABILITY NORMAL, SQL*Net transparently redirects connections. With AVAILABILITY MAX, the original listener is reconfigured with a forwarding address

Manual

Complete all of the following before beginning the relocation. All SQL commands run as SYSDBA.

1. Verify ARCHIVELOG mode on the target CDB

The target CDB must be in ARCHIVELOG mode for the relocated PDB to open READ WRITE. Without ARCHIVELOG, the PDB can only open READ ONLY. No ARCHIVELOG requirement exists for the source CDB.

-- Connected to {TARGET_CDB} as SYSDBA
SELECT log_mode FROM v$database;

Expected output:

LOG_MODE
------------
ARCHIVELOG

If the target CDB is not in ARCHIVELOG mode, enable it:

-- Connected to {TARGET_CDB} as SYSDBA
SHUTDOWN IMMEDIATE;
STARTUP MOUNT;
ALTER DATABASE ARCHIVELOG;
ALTER DATABASE OPEN;

2. Verify LOCAL UNDO mode on the source CDB

The source CDB must be in local undo mode. No LOCAL UNDO requirement exists for the target CDB.

-- Connected to {SOURCE_CDB} as SYSDBA
SELECT property_value FROM database_properties
WHERE property_name = 'LOCAL_UNDO_ENABLED';

Expected output:

PROPERTY_VALUE
--------------
TRUE

If local undo is not enabled:

-- Connected to {SOURCE_CDB} as SYSDBA
ALTER DATABASE LOCAL UNDO ON;
SHUTDOWN IMMEDIATE;
STARTUP;

3. Verify COMPATIBLE parameter compatibility

The COMPATIBLE parameter on the source CDB must be less than or equal to the target CDB.

-- Run on BOTH CDBs
SHOW PARAMETER compatible

Expected output:

NAME        TYPE   VALUE
----------- ------ ----------
compatible  string 19.0.0

4. Verify character set compatibility

If the target CDB is not AL32UTF8, confirm character sets are compatible.

-- Run on BOTH CDBs
SELECT value FROM nls_database_parameters
WHERE parameter IN ('NLS_CHARACTERSET', 'NLS_NCHAR_CHARACTERSET');

5. Verify database options compatibility

Database options installed on the source must be the same as or a subset of the target.

-- Run on BOTH CDBs
SELECT comp_name, status FROM dba_registry WHERE status = 'VALID';

6. Create a common user on the source CDB

Create a common user with CREATE SESSION and CREATE PLUGGABLE DATABASE privileges. The database link from the target CDB connects through this user.

-- Connected to {SOURCE_CDB} as SYSDBA
CREATE USER {C##REMOTE_CLONE_USER} IDENTIFIED BY {password} CONTAINER=ALL;
GRANT CREATE SESSION, CREATE PLUGGABLE DATABASE TO {C##REMOTE_CLONE_USER} CONTAINER=ALL;

Note: Oracle requires CREATE SESSION plus either CREATE PLUGGABLE DATABASE or SYSOPER. CREATE PLUGGABLE DATABASE is the least-privilege option.

7. Configure TNS connectivity from the target to the source

Add a tnsnames.ora entry on the target CDB host that connects to the source CDB. The entry must include (SERVER = DEDICATED).

Warning: Omitting SERVER = DEDICATED causes ORA-01031: insufficient privileges during relocation. This is a common pitfall.

Add to {ORACLE_HOME}/network/admin/tnsnames.ora on the target host:

{SOURCE_CDB} =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = {SOURCE_HOST})(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = {SOURCE_CDB})
    )
  )

Test the connection:

tnsping {SOURCE_CDB}

Expected output:

OK (10 msec)

8. Create a database link on the target CDB

Create a database link in the target CDB root container that connects to the source CDB root via the common user.

-- Connected to {TARGET_CDB} as SYSDBA
CREATE PUBLIC DATABASE LINK {CLONE_LINK}
  CONNECT TO {C##REMOTE_CLONE_USER} IDENTIFIED BY {password}
  USING '{SOURCE_CDB}';

Test the database link:

-- Connected to {TARGET_CDB} as SYSDBA
SELECT db_unique_name FROM v$database@{CLONE_LINK};

Expected output:

DB_UNIQUE_NAME
--------------
{SOURCE_CDB}

9. Verify Oracle Managed Files or plan file name conversion

Confirm OMF is configured on the target CDB:

-- Connected to {TARGET_CDB} as SYSDBA
SHOW PARAMETER db_create_file_dest

Expected output:

NAME                 TYPE   VALUE
-------------------- ------ ----------------------------------------
db_create_file_dest  string /u01/app/oracle/oradata

If OMF is not configured, use CREATE_FILE_DEST or FILE_NAME_CONVERT in the CREATE PLUGGABLE DATABASE statement (shown in the relocation step).

10. Verify listener topology

Determine the listener configuration for both CDBs:

Topology AVAILABILITY Mode Action
Both CDBs share a listener NORMAL (default) No additional configuration. SQL*Net handles redirection.
Cross-registered listeners (LOCAL_LISTENER + REMOTE_LISTENER) NORMAL No additional configuration. Services are visible across the listener network.
Isolated listener networks (separate data centers) MAX Use AVAILABILITY MAX in the relocate command.

11. Back up the source PDB

Warning: If relocation fails, the PDB may enter UNUSABLE state and can only be dropped. A pre-relocation backup is essential.

export ORACLE_SID={SOURCE_CDB}
rman target /
BACKUP PLUGGABLE DATABASE {RELOCATE_PDB} PLUS ARCHIVELOG;

Choose AVAILABILITY Mode

Select the appropriate mode before executing the relocation:

Mode When to Use Behavior
AVAILABILITY NORMAL (default) Both CDBs share a listener or use cross-registered listeners SQL*Net transparently forwards connections. Source PDB is removed after relocation. No tombstone PDB.
AVAILABILITY MAX CDBs use isolated listener networks (e.g., cross-data-center relocation) Listener forwarding is configured automatically via LISTENER_NETWORKS. A tombstone PDB with status RELOCATED remains in the source CDB until manually dropped.

Relocation

Step 1: Connect to the target CDB

export ORACLE_SID={TARGET_CDB}
sqlplus / as sysdba

Step 2: Execute the relocation

With OMF (standard):

-- Connected to {TARGET_CDB} as SYSDBA
CREATE PLUGGABLE DATABASE {RELOCATE_PDB}
  FROM {RELOCATE_PDB}@{CLONE_LINK}
  RELOCATE
  AVAILABILITY NORMAL;

Expected output:

Pluggable database created.

With AVAILABILITY MAX:

-- Connected to {TARGET_CDB} as SYSDBA
CREATE PLUGGABLE DATABASE {RELOCATE_PDB}
  FROM {RELOCATE_PDB}@{CLONE_LINK}
  RELOCATE
  AVAILABILITY MAX;

Without OMF (using FILE_NAME_CONVERT):

-- Connected to {TARGET_CDB} as SYSDBA
CREATE PLUGGABLE DATABASE {RELOCATE_PDB}
  FROM {RELOCATE_PDB}@{CLONE_LINK}
  RELOCATE
  AVAILABILITY NORMAL
  FILE_NAME_CONVERT = (
    '/u01/app/oracle/oradata/{SOURCE_CDB}/{RELOCATE_PDB}/',
    '/u01/app/oracle/oradata/{TARGET_CDB}/{RELOCATE_PDB}/'
  );

Without OMF (using CREATE_FILE_DEST):

-- Connected to {TARGET_CDB} as SYSDBA
CREATE PLUGGABLE DATABASE {RELOCATE_PDB}
  FROM {RELOCATE_PDB}@{CLONE_LINK}
  RELOCATE
  AVAILABILITY NORMAL
  CREATE_FILE_DEST = '/u01/app/oracle/oradata/{TARGET_CDB}';

Note for ASM environments: Use ASM disk group paths in FILE_NAME_CONVERT or CREATE_FILE_DEST:

FILE_NAME_CONVERT = ('+DATA/{SOURCE_CDB}/', '+DATA/{TARGET_CDB}/')

Or:

CREATE_FILE_DEST = '+DATA'

After the CREATE PLUGGABLE DATABASE command returns, the PDB is in MOUNTED state with status RELOCATING. The hot clone phase is in progress. The source PDB remains open and fully operational.

Step 3: Monitor relocation progress

-- Connected to {TARGET_CDB} as SYSDBA
SELECT opname, sofar, totalwork,
       ROUND(100 * sofar / NULLIF(totalwork, 0), 2) AS pct_complete
FROM v$session_longops
WHERE opname IN ('kpdbfCopyTaskCbk', 'kcrfremnoc')
ORDER BY opname;

Expected output:

OPNAME              SOFAR  TOTALWORK  PCT_COMPLETE
------------------- ------ ---------- ------------
kcrfremnoc              12         12       100.00
kpdbfCopyTaskCbk       450        450       100.00

kpdbfCopyTaskCbk tracks datafile copy progress. kcrfremnoc tracks redo file copy progress.

Check PDB status during relocation:

-- Connected to {TARGET_CDB} as SYSDBA
SELECT pdb_name, status FROM dba_pdbs WHERE pdb_name = '{RELOCATE_PDB}';

Expected output:

PDB_NAME         STATUS
---------------- ----------
{RELOCATE_PDB}   RELOCATING

Step 4: Open the PDB to complete the relocation

This triggers the switchover: end SCN marker, media recovery, session draining, source PDB closure, and target PDB open.

-- Connected to {TARGET_CDB} as SYSDBA
ALTER PLUGGABLE DATABASE {RELOCATE_PDB} OPEN;

Expected output:

Pluggable database altered.

Note: The PDB must be opened in READ WRITE mode. Opening in READ ONLY mode returns an error. The OPEN command without qualifiers opens in READ WRITE mode, which is correct.

Validation

Quick check

-- Connected to {TARGET_CDB} as SYSDBA
SHOW PDBS

Expected output:

    CON_ID CON_NAME                       OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
         2 PDB$SEED                       READ ONLY  NO
         3 {RELOCATE_PDB}                 READ WRITE NO

The relocated PDB appears in READ WRITE mode with RESTRICTED = NO.

Full validation

1. PDB status via V$PDBS

-- Connected to {TARGET_CDB} as SYSDBA
SELECT con_id, name, open_mode, restricted FROM v$pdbs WHERE name = '{RELOCATE_PDB}';

Expected output:

CON_ID NAME              OPEN_MODE  RES
------ ----------------- ---------- ---
     3 {RELOCATE_PDB}    READ WRITE NO

2. PDB status via DBA_PDBS

-- Connected to {TARGET_CDB} as SYSDBA
SELECT pdb_name, status FROM dba_pdbs WHERE pdb_name = '{RELOCATE_PDB}';

Expected output:

PDB_NAME           STATUS
------------------ ------
{RELOCATE_PDB}     NORMAL

Status must be NORMAL. A status of RELOCATING means the PDB has not been opened yet. A status of UNUSABLE means the relocation failed.

3. Plug-in violations check

-- Connected to {TARGET_CDB} as SYSDBA
SELECT name, cause, type, message, status
FROM pdb_plug_in_violations
WHERE name = '{RELOCATE_PDB}' AND type = 'ERROR' AND status <> 'RESOLVED';

Expected output:

no rows selected

No unresolved ERROR rows should exist.

4. Component status inside the PDB

-- Connected to {TARGET_CDB} as SYSDBA
ALTER SESSION SET CONTAINER = {RELOCATE_PDB};
SELECT comp_name, version, status FROM dba_registry;

All components must show VALID.

5. Invalid objects check

-- Connected to {TARGET_CDB} as SYSDBA, container = {RELOCATE_PDB}
SELECT COUNT(*) AS invalid_count FROM dba_objects WHERE status = 'INVALID';

Expected output:

INVALID_COUNT
-------------
            0

If invalid objects appear, recompile:

@$ORACLE_HOME/rdbms/admin/utlrp.sql

6. Verify source CDB cleanup (AVAILABILITY NORMAL)

-- Connected to {SOURCE_CDB} as SYSDBA
SHOW PDBS

The relocated PDB no longer appears in the source CDB.

7. Verify tombstone PDB (AVAILABILITY MAX only)

-- Connected to {SOURCE_CDB} as SYSDBA
SELECT pdb_name, status FROM dba_pdbs WHERE pdb_name = '{RELOCATE_PDB}';

Expected output:

PDB_NAME           STATUS
------------------ ---------
{RELOCATE_PDB}     RELOCATED

The tombstone PDB remains until manually dropped (see Post-Relocation Tasks).

Post-Relocation Tasks

Step 1: Save PDB state

Ensure the PDB opens automatically when the target CDB restarts.

-- Connected to {TARGET_CDB} as SYSDBA
ALTER PLUGGABLE DATABASE {RELOCATE_PDB} SAVE STATE;

Expected output:

Pluggable database altered.

Step 2: Back up the relocated PDB

The relocated PDB cannot be recovered unless it is backed up in the target CDB. An RMAN backup is required immediately.

export ORACLE_SID={TARGET_CDB}
rman target /
BACKUP PLUGGABLE DATABASE {RELOCATE_PDB} PLUS ARCHIVELOG;

Step 3: Drop the database link

The database link is no longer needed after relocation.

-- Connected to {TARGET_CDB} as SYSDBA
DROP PUBLIC DATABASE LINK {CLONE_LINK};

Step 4: Drop the tombstone PDB (AVAILABILITY MAX only)

After updating all application connection strings to point to the target CDB, drop the tombstone PDB from the source CDB.

Warning: This permanently destroys the tombstone PDB and its datafiles. Ensure all application connection strings have been updated and tested against the target CDB before proceeding.

-- Connected to {SOURCE_CDB} as SYSDBA
DROP PLUGGABLE DATABASE {RELOCATE_PDB} INCLUDING DATAFILES;

Step 5: Clean up the common user (optional)

If the common user is no longer needed on the source CDB:

-- Connected to {SOURCE_CDB} as SYSDBA
DROP USER {C##REMOTE_CLONE_USER} CASCADE;

DBCA Alternative

Oracle 19c provides dbca -relocatePDB as a single-command alternative that automates database link creation.

Note: The DBCA method requires both CDBs to be in ARCHIVELOG mode (unlike the SQL method, which only requires the target CDB). It also requires the remote (source) CDB to be in local undo mode. If the source CDB is not in ARCHIVELOG mode, enable it before using DBCA (see Prerequisite 1 for steps).

The DBCA method additionally requires the SYS password for both CDBs (unlike the SQL method, which only uses the common user credentials).

The -sourceDB parameter specifies the local (target) CDB despite its name. The -remoteDBConnString parameter specifies the remote (source) CDB connection. DBCA creates and drops the database link automatically.

dbca -silent \
  -relocatePDB \
  -pdbName {RELOCATE_PDB} \
  -sourceDB {TARGET_CDB} \
  -remotePDBName {RELOCATE_PDB} \
  -remoteDBConnString {SOURCE_HOST}:1521/{SOURCE_CDB} \
  -remoteDBSYSDBAUserName SYS \
  -remoteDBSYSDBAUserPassword {SOURCE_SYS_PASSWORD} \
  -sysDBAUserName SYS \
  -sysDBAPassword {TARGET_SYS_PASSWORD} \
  -dbLinkUsername {C##REMOTE_CLONE_USER} \
  -dbLinkUserPassword {password}

Expected output:

Prepare for db operation
50% complete
Create pluggable database using relocate PDB operation
100% complete
Pluggable database "{RELOCATE_PDB}" plugged successfully.

If DBCA fails, check the DBCA log for details: $ORACLE_BASE/cfgtoollogs/dbca/.

Troubleshooting

Problem Cause Solution
ORA-01031: insufficient privileges during relocation TNS entry for the database link is missing (SERVER = DEDICATED) Add (SERVER = DEDICATED) to the CONNECT_DATA section of the tnsnames.ora entry for the source CDB on the target host. Recreate the database link.
ORA-65005: missing or invalid file name pattern Common user default tablespace does not exist in the target CDB (Bug 19174942) Create the missing tablespace in the target CDB root, or create the common user with DEFAULT TABLESPACE USERS on the source CDB.
ORA-65046: character set mismatch Target CDB character set is not AL32UTF8 and is incompatible with the PDB's character set Recreate the target CDB with AL32UTF8, or use a CDB with a compatible character set.
ORA-65188: cannot relocate with AVAILABILITY MAX Cross-version relocation attempted with AVAILABILITY MAX Use AVAILABILITY NORMAL (or omit the clause) for cross-version relocation. Run dbupgrade after opening the PDB.
PDB in UNUSABLE state after failed relocation An error occurred during CREATE PLUGGABLE DATABASE ... RELOCATE Check the alert log: $ORACLE_BASE/diag/rdbms/{target_cdb}/{TARGET_CDB}/trace/alert_{TARGET_CDB}.log. Drop the unusable PDB (DROP PLUGGABLE DATABASE {RELOCATE_PDB} INCLUDING DATAFILES;), fix the root cause, and retry.
PDB stuck in RELOCATING status Relocation is still in progress, or failed mid-way before completion Check V$SESSION_LONGOPS for ongoing copy operations. If no active operations exist, check the alert log. The PDB may need to be dropped and the relocation retried.
Sessions not draining during switchover Long-running transactions or sessions without request boundaries Application Continuity handles failover automatically for eligible sessions. For sessions that cannot be drained, the database invokes automatic failover. Verify Application Continuity is configured on services.
ALLOW_MULTIPLE_REDIRECTS not set for RAC SCAN listeners SCAN listener rejects the second redirect during AVAILABILITY MAX relocation in a RAC environment Set ALLOW_MULTIPLE_REDIRECTS_LISTENER_SCAN1=YES (and SCAN2, SCAN3) in listener.ora on every cluster node. Do NOT set this for node listeners -- it causes infinite redirect loops.
PDB opens in RESTRICTED mode Pending plug-in violations or patch-level differences between CDBs Query PDB_PLUG_IN_VIOLATIONS for unresolved errors. Run $ORACLE_HOME/OPatch/datapatch -verbose if patch differences exist. Close and reopen the PDB.
Database link test returns ORA-12154 or ORA-01017 TNS alias missing or wrong in tnsnames.ora, credentials incorrect, firewall blocking port 1521 Verify the TNS entry exists and resolves (tnsping {SOURCE_CDB}). Test connectivity (sqlplus {C##REMOTE_CLONE_USER}/{password}@{SOURCE_CDB}). Check firewall rules for port 1521. See Prerequisites 7 and 8.

References