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
COMPATIBLEinitialization 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_destis set). AFILE_NAME_CONVERTalternative 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). WithAVAILABILITY MAX, a tombstone PDB with statusRELOCATEDremains 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. WithAVAILABILITY 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 SESSIONplus eitherCREATE PLUGGABLE DATABASEorSYSOPER.CREATE PLUGGABLE DATABASEis 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 = DEDICATEDcausesORA-01031: insufficient privilegesduring 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_CONVERTorCREATE_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
OPENcommand 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. |