What Is Oracle ZDM?
Oracle Zero Downtime Migration (ZDM) is Oracle's own tooling for migrating Oracle databases with minimal or zero application downtime. Introduced alongside Oracle Database 19c, it has matured significantly through 21c and 23ai patch cycles.
ZDM handles the complexity of database migration by orchestrating:
- Physical or logical replication to the target while your source stays live
- Continuous synchronization during the migration window
- A coordinated switchover that completes in 2–15 minutes
Architecture Overview
ZDM uses three distinct tiers:
ZDM Service Host — A dedicated server or VM where the ZDM software is installed. This host orchestrates the migration but processes no data itself. It needs SSH access to both source and target database hosts.
Source Database Host — Your existing production Oracle server. ZDM connects here to take backups, configure Data Guard, or drive a Data Pump export.
Target Database Host — The destination. For cloud migrations this is typically an Oracle Base Database Service or ExaCS instance. For on-premises targets it is any Oracle-supported Linux host.
The ZDM service coordinates everything through a sequential phase model: it SSH's into both endpoints, executes remote commands, and tracks migration progress through a series of named phases with checkpoint/resume capability.
Migration Methods: Physical vs Logical
ZDM offers three migration methods, and the choice matters enormously for large databases:
Physical Migration (RMAN-based) — Uses RMAN backup and restore to transfer the database to the target, then configures a Data Guard standby for ongoing redo apply. Switchover is a Data Guard role change. Fastest for large databases (multi-TB). Requires compatible OS and endian format between source and target.
Logical Migration (Data Pump-based) — Exports schema and data using Oracle Data Pump, with optional GoldenGate for continuous replication. Required for cross-platform, cross-version, or cross-endian migrations. Slower for large databases but more flexible.
Online Logical Migration — Combines Data Pump for the initial load with GoldenGate Microservices for continuous replication. True near-zero downtime. Requires GoldenGate licensing.
For most lift-and-shift migrations to OCI, physical migration is the right choice. You get faster transfer times and a simpler change model.
Prerequisites Checklist
Before you run a single zdmcli command, verify each of these:
Network and SSH Connectivity
# From ZDM host — test passwordless SSH to both source and target
ssh -i /home/zdmuser/.ssh/id_rsa oracle@sourcehost "echo OK"
ssh -i /home/zdmuser/.ssh/id_rsa oracle@targethost "echo OK"
Verify oracle user has passwordless sudo
ssh oracle@sourcehost "sudo /bin/ls /etc/oratab"
Oracle Database Versions
- ZDM software version should be >= your target Oracle version
- Source DB minimum: 11.2.0.4 for physical migration, 12.1.0.2 for logical
- Target: same version or higher than source
Wallets and sys Credentials
# Create source wallet with MKSTORE
mkstore -wrl /home/zdmuser/wallets/src -create
mkstore -wrl /home/zdmuser/wallets/src -createCredential "sourcehost:1521/PRODDB" sys
Create target wallet
mkstore -wrl /home/zdmuser/wallets/tgt -create
mkstore -wrl /home/zdmuser/wallets/tgt -createCredential "targethost:1521/PRODDB_TGT" sys
Create sqlnet.ora on ZDM host pointing to wallet
cat > $ORACLE_HOME/network/admin/sqlnet.ora <<EOF
WALLET_LOCATION = (SOURCE = (METHOD = FILE)(METHOD_DATA = (DIRECTORY = /home/zdmuser/wallets/src)))
SQLNET.WALLET_OVERRIDE = TRUE
EOF
Disk Space
- ZDM host: 30+ GB for software and working logs
- Source: enough for RMAN backup (use
RMAN_COMPRESSION_ALGORITHM=MEDIUMto reduce) - OCI Object Storage bucket: pre-created with correct compartment permissions
Starting the ZDM Service
export ZDM_HOME=/u01/zdmhome
export ZDM_BASE=/u01/zdmbase
Start
$ZDM_HOME/bin/zdmservice start
Verify
$ZDM_HOME/bin/zdmservice status
Expected:
ZDM Service is up and running.
Listening on port: 8895
Logs go here if something is wrong
tail -100 $ZDM_BASE/zdm/log/zdm_service.log
The Response File
The response file is the single most important artefact in the migration. Every parameter lives here.
# /home/zdmuser/response/prod_to_oci.rsp
Target DB unique name (must match what you provisioned on OCI)
TGT_DB_UNIQUE_NAME=PRODDB_TGT
Physical migration using Data Guard replication
MIGRATION_METHOD=ONLINE_PHYSICAL
Transfer data via OCI Object Storage
DATA_TRANSFER_MEDIUM=OSS
HOST=https://objectstorage.us-ashburn-1.oraclecloud.com
OPC_CONTAINER=zdm-migration-bucket
RMAN compression — reduces transfer time significantly for large DBs
RMAN_COMPRESSION_ALGORITHM=MEDIUM
Run datapatch on target post-switchover (recommended: TRUE)
TGT_SKIP_DATAPATCH=FALSE
Source DB unique name
SRC_DB_UNIQUE_NAME=PRODDB
Keep source running after switchover until you confirm target is stable
SHUTDOWN_SOURCE=FALSE
Key Parameters Explained
MIGRATION_METHOD — This is the fundamental choice. ONLINE_PHYSICAL gives you live Data Guard sync with a rapid switchover. OFFLINE_PHYSICAL is a backup/restore with no sync. ONLINE_LOGICAL requires GoldenGate.
DATA_TRANSFER_MEDIUM — OSS uses OCI Object Storage (fast, scalable, recommended for anything >100GB). DBLINK transfers directly over SQL*Net (simpler setup, but slower for large DBs). NFS works for collocated target.
TGT_SKIP_DATAPATCH — Only set TRUE if you're doing a test migration and want to save time. For production migrations, always FALSE. Skipping datapatch can leave objects in an invalid state.
Running the Migration
$ZDM_HOME/bin/zdmcli migrate database \
-sourcedb PRODDB \
-sourcenode sourcehost.example.com \
-srcauth zdmauth \
-srcarg1 user:oracle \
-srcarg2 identity_file:/home/zdmuser/.ssh/id_rsa \
-srcarg3 sudo_location:/usr/bin/sudo \
-targetnode targethost.oci.example.com \
-tgtauth zdmauth \
-tgtarg1 user:oracle \
-tgtarg2 identity_file:/home/zdmuser/.ssh/id_rsa \
-tgtarg3 sudo_location:/usr/bin/sudo \
-rsp /home/zdmuser/response/prod_to_oci.rsp \
-sourcesyswallet /home/zdmuser/wallets/src \
-targetsyswallet /home/zdmuser/wallets/tgt
Returns immediately with a job ID
Job ID: 1
Important: ZDM submits the job and returns immediately. The migration runs asynchronously. Do not close your terminal session — use screen or tmux for long migrations.
Monitoring with zdmcli query job
# Poll current status
$ZDM_HOME/bin/zdmcli query job -jobid 1
Watch it live (runs every 60s)
watch -n 60 "$ZDM_HOME/bin/zdmcli query job -jobid 1"
Phase-by-Phase Breakdown
| Phase | Duration (typical) | What Happens |
|-------|-------------------|-------------|
| SETUP | 2–5 min | Creates working dirs, validates SSH, checks Oracle Net |
| VALIDATESOURCE | 1–2 min | Connects to source DB, checks version, mode, archive log |
| VALIDATETARGET | 1–2 min | Connects to target DB, checks provisioning |
| INITIALTRANSFER | Hours | RMAN backup from source → OCI Object Storage; restore to target |
| SYNCTARGET | Ongoing | Archive log apply loop — keeps target current |
| SWITCHOVER | 2–15 min | Role change: source → standby, target → primary |
| POSTSWITCHOVER | 30–60 min | TNS config update, datapatch if enabled, cleanup |
The Switchover Decision
ZDM pauses in SYNCTARGET and waits for you to initiate switchover. Check the apply lag before proceeding:
-- On target: check Data Guard apply lag
SELECT NAME, VALUE, UNIT FROM V$DATAGUARD_STATS WHERE NAME IN ('apply lag','transport lag');
-- Acceptable: apply lag < 30 seconds
When you are ready:
$ZDM_HOME/bin/zdmcli resume job -jobid 1
Common Failures and Fixes
SSH Authentication Failures
Error: SSH connection to sourcehost failed — Permission denied (publickey)
Fix: Verify the identity file path is correct and the public key is in the oracle user's authorized_keys on both source and target.
Wallet Cannot Open
ORA-28353: failed to open wallet
Check that the wallet path in your sqlnet.ora on the ZDM host matches where you created the wallet, and that the wallet contains the correct credential. Use mkstore -wrl /path/to/wallet -listCredential to verify.
Archive Log Destination Full
-- On source during SYNCTARGET
SELECT DEST_ID, STATUS, ERROR FROM V$ARCHIVE_DEST WHERE STATUS != 'INACTIVE';
ALTER SYSTEM SET DB_RECOVERY_FILE_DEST_SIZE = 500G SCOPE=BOTH;
Object Storage Auth Errors
# Test OCI OS connectivity from ZDM host
oci os bucket list --compartment-id <ocid> --namespace <namespace>
Post-Migration Validation
-- 1. Confirm database role and mode
SELECT NAME, DB_UNIQUE_NAME, DATABASE_ROLE, OPEN_MODE FROM V$DATABASE;
-- 2. Check for invalid objects
SELECT OWNER, COUNT(*) CNT FROM DBA_OBJECTS
WHERE STATUS = 'INVALID'
GROUP BY OWNER ORDER BY 2 DESC;
-- 3. Verify key schemas accessible
SELECT USERNAME, ACCOUNT_STATUS FROM DBA_USERS
WHERE ACCOUNT_STATUS = 'OPEN' ORDER BY USERNAME;
TuneVault and Post-Migration Health
The 48 hours after a ZDM migration are the highest-risk period. TuneVault's automated health checks surface the common post-migration issues — missing optimizer statistics, tablespace sizing differences, redo log configuration, and invalid objects — within minutes of pointing at the new instance.