Physical Standby with Data Guard Broker
RMAN Active Duplicate, standby redo logs, Broker configuration, real-time apply, and manual switchover — a validated implementation pattern.
Table of contents
- Objective
- Target architecture
- Prerequisites & pre-checks
- Configure Oracle Net & listener
- Create the standby instance
- RMAN Active Database Duplicate
- Validate the physical standby
- Standby redo logs
- Configure & enable Broker
- Validate transport & apply
- Planned switchover test
- Troubleshooting
- Production checklist
- Conclusion
Objective
Build an Oracle Database 19c physical standby using RMAN Active Database Duplicate, then configure Data Guard Broker for a Broker-managed configuration with asynchronous redo transport and real-time apply. Fast-Start Failover (FSFO) is intentionally disabled; role transitions stay manual and operator-controlled.
Naming used throughout this guide: DB_NAME=DATAVERLABS, primary DB_UNIQUE_NAME=VERADBPRD, standby DB_UNIQUE_NAME=VERADBPRD_DR, Broker configuration DATAVERLABS_DG. Hostnames (dataveraproddb.dataveralabs.local / dataveraproddbdr.dataveralabs.local) are documentation placeholders — replace with your actual FQDNs.
Target architecture
Oracle Data Guard
ASYNC
+----------------------------------+
| |
v |
PRIMARY STANDBY
VERADBPRD VERADBPRD_DR
DB_NAME=DATAVERLABS DB_NAME=DATAVERLABS
READ WRITE MOUNTED
| |
+---------- Redo Transport --------+
Broker Configuration: DATAVERLABS_DG
Protection Mode: MaxPerformance
FSFO: Disabled
Apply Delay: 0 minutesPrerequisites & pre-checks
Confirm the primary is in ARCHIVELOG mode, is the expected primary, and has FORCE LOGGING enabled before touching anything else.
SELECT NAME, DB_UNIQUE_NAME, DATABASE_ROLE, OPEN_MODE,
LOG_MODE, FORCE_LOGGING
FROM V$DATABASE;Expected result DATABASE_ROLE=PRIMARY, OPEN_MODE=READ WRITE, LOG_MODE=ARCHIVELOG, FORCE_LOGGING=YES.
SELECT GROUP#, THREAD#, BYTES/1024/1024 AS SIZE_MB, STATUS
FROM V$LOG
ORDER BY GROUP#;Expected result Reference design: 5 online redo groups, Thread 1, 10,240 MB each.
Verify ASM has enough free space in +DATA and +REDO for the database copy, online redo, standby redo logs, and headroom for growth:
SELECT NAME, TOTAL_MB, FREE_MB,
ROUND(FREE_MB/TOTAL_MB*100,2) AS FREE_PCT
FROM V$ASM_DISKGROUP
ORDER BY NAME;Configure Oracle Net & listener
Configure matching TNS aliases on both servers — replace placeholder hostnames with your real primary and DR hosts.
VERADBPRD =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = dataveraproddb.dataveralabs.local)(PORT = 1610))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = VERADBPRD)
)
)
VERADBPRD_DR =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = dataveraproddbdr.dataveralabs.local)(PORT = 1610))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = VERADBPRD_DR)
)
(UR = A)
)
VERADBPRD_DR_DGMGRL =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = dataveraproddbdr.dataveralabs.local)(PORT = 1610))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = VERADBPRD_DR_DGMGRL)
)
)tnsping VERADBPRD
tnsping VERADBPRD_DR
tnsping VERADBPRD_DR_DGMGRLExpected result All three aliases resolve. TNS-03505 means the alias isn’t visible from the active Oracle Net configuration — see Troubleshooting.
Standby listener configuration:
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)
(HOST = dataveraproddbdr.dataveralabs.local)
(PORT = 1610))
)
)
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(GLOBAL_DBNAME = VERADBPRD_DR)
(SID_NAME = VERADBPRD_DR)
(ORACLE_HOME = /u01/app/oracle/product/19.0.0/db_1)
)
(SID_DESC =
(GLOBAL_DBNAME = VERADBPRD_DR_DGMGRL)
(SID_NAME = VERADBPRD_DR)
(ORACLE_HOME = /u01/app/oracle/product/19.0.0/db_1)
)
)
ENABLE_GLOBAL_DYNAMIC_ENDPOINT_LISTENER = ON
VALID_NODE_CHECKING_REGISTRATION_LISTENER = ONExpected result lsnrctl status LISTENER — the static Broker service may show UNKNOWN before dynamic registration; this is normal for a static SID entry.
Create the standby instance directory structure and a dummy pfile
export ORACLE_BASE=/u01/app/oracle
export ORACLE_SID=VERADBPRD_DR
export ORACLE_HOME=$ORACLE_BASE/product/19.0.0/db_1
export TNS_ADMIN=$ORACLE_HOME/network/admin
export PATH=$ORACLE_HOME/bin:/usr/bin:/bin:$PATH
export LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib:/usr/local/lib*.db_name='DATAVERLABS'
*.db_unique_name='VERADBPRD_DR'
*.db_block_size=8192
*.compatible='19.0.0'
*.db_files=5000
*.db_create_file_dest='+DATA'
*.remote_login_passwordfile='EXCLUSIVE'
*.sga_target=77158m
*.pga_aggregate_target=25720m
*.processes=3000
*.sessions=4536
*.open_cursors=800
*.enable_pluggable_database=true
*.undo_tablespace='UNDOTBS1'
*.undo_retention=4500
*.audit_trail='db'
*.diagnostic_dest='/u01/app/oracle'
*.audit_file_dest='/u01/app/oracle/admin/VERADBPRD_DR/adump'sqlplus / as sysdba
STARTUP NOMOUNT PFILE='/path/to/standby_init.ora';Expected result: Standby instance starts in NOMOUNT.
RMAN Active Database Duplicate
Connect to the primary as TARGET and the standby as AUXILIARY.
rman target "sys@VERADBPRD" auxiliary "sys@VERADBPRD_DR"
RUN {
ALLOCATE CHANNEL c1 DEVICE TYPE DISK;
ALLOCATE CHANNEL c2 DEVICE TYPE DISK;
ALLOCATE CHANNEL c3 DEVICE TYPE DISK;
ALLOCATE CHANNEL c4 DEVICE TYPE DISK;
ALLOCATE AUXILIARY CHANNEL a1 DEVICE TYPE DISK;
ALLOCATE AUXILIARY CHANNEL a2 DEVICE TYPE DISK;
ALLOCATE AUXILIARY CHANNEL a3 DEVICE TYPE DISK;
ALLOCATE AUXILIARY CHANNEL a4 DEVICE TYPE DISK;
DUPLICATE TARGET DATABASE
FOR STANDBY
FROM ACTIVE DATABASE
DORECOVER
SPFILE
SET db_unique_name='VERADBPRD_DR'
SET db_create_file_dest='+DATA'
SET db_create_online_log_dest_1='+REDO'
SET standby_file_management='AUTO'
SET audit_file_dest='/u01/app/oracle/admin/VERADBPRD_DR/adump'
NOFILENAMECHECK;
}Expected result RMAN completes the duplicate and recovery without errors.
DBA note Use NOFILENAMECHECK only when primary and standby have independent storage/file systems and the file layout makes it safe.
Validate the physical standby
SELECT NAME, DB_UNIQUE_NAME, DATABASE_ROLE,
OPEN_MODE, CONTROLFILE_TYPE
FROM V$DATABASE;Expected result NAME=DATAVERLABS, DB_UNIQUE_NAME=VERADBPRD_DR, DATABASE_ROLE=PHYSICAL STANDBY, OPEN_MODE=MOUNTED, CONTROLFILE_TYPE=STANDBY.
Standby redo logs (both databases)
Critical for Broker validation and real-time apply. For 5 × 10 GB primary online redo groups, create 6 × 10 GB SRLs per database, all on Thread 1.
Standby SRLs
ALTER DATABASE ADD STANDBY LOGFILE THREAD 1 GROUP 6 '+REDO' SIZE 10G;
ALTER DATABASE ADD STANDBY LOGFILE THREAD 1 GROUP 7 '+REDO' SIZE 10G;
ALTER DATABASE ADD STANDBY LOGFILE THREAD 1 GROUP 8 '+REDO' SIZE 10G;
ALTER DATABASE ADD STANDBY LOGFILE THREAD 1 GROUP 9 '+REDO' SIZE 10G;
ALTER DATABASE ADD STANDBY LOGFILE THREAD 1 GROUP 10 '+REDO' SIZE 10G;
ALTER DATABASE ADD STANDBY LOGFILE THREAD 1 GROUP 11 '+REDO' SIZE 10G;Primary SRLs
ALTER DATABASE ADD STANDBY LOGFILE THREAD 1 GROUP 6 '+REDO' SIZE 10G;
ALTER DATABASE ADD STANDBY LOGFILE THREAD 1 GROUP 7 '+REDO' SIZE 10G;
ALTER DATABASE ADD STANDBY LOGFILE THREAD 1 GROUP 8 '+REDO' SIZE 10G;
ALTER DATABASE ADD STANDBY LOGFILE THREAD 1 GROUP 9 '+REDO' SIZE 10G;
ALTER DATABASE ADD STANDBY LOGFILE THREAD 1 GROUP 10 '+REDO' SIZE 10G;
ALTER DATABASE ADD STANDBY LOGFILE THREAD 1 GROUP 11 '+REDO' SIZE 10G;SELECT GROUP#, THREAD#, BYTES/1024/1024 AS SIZE_MB, STATUS
FROM V$STANDBY_LOG
ORDER BY GROUP#;Expected result Six SRLs, all Thread 1, each 10,240 MB. On an active standby, one may show ACTIVE, the rest UNASSIGNED.
DBA note Do not create SRLs with THREAD#=0 for a single-thread design — see ORA-16789 in Troubleshooting.
Configure & enable Broker
Broker files in ASM — primary
ALTER SYSTEM SET DG_BROKER_CONFIG_FILE1=
'+DATA/VERADBPRD/BROKER/dr1VERADBPRD.dat'
SCOPE=SPFILE;
ALTER SYSTEM SET DG_BROKER_CONFIG_FILE2=
'+REDO/VERADBPRD/BROKER/dr2VERADBPRD.dat'
SCOPE=SPFILE;Broker files in ASM — standby
ALTER SYSTEM SET DG_BROKER_CONFIG_FILE1=
'+DATA/VERADBPRD_DR/BROKER/dr1VERADBPRD_DR.dat'
SCOPE=SPFILE;
ALTER SYSTEM SET DG_BROKER_CONFIG_FILE2=
'+REDO/VERADBPRD_DR/BROKER/dr2VERADBPRD_DR.dat'
SCOPE=SPFILE;ALTER SYSTEM SET DG_BROKER_START=TRUE SCOPE=BOTH;Expected result DG_BROKER_START=TRUE on both databases; each reports its own +DATA/+REDO Broker file paths.
Create the Broker configuration:
dgmgrl /
CREATE CONFIGURATION 'DATAVERLABS_DG'
AS PRIMARY DATABASE IS 'VERADBPRD'
CONNECT IDENTIFIER IS 'VERADBPRD';
ADD DATABASE 'VERADBPRD_DR'
AS CONNECT IDENTIFIER IS 'VERADBPRD_DR'
MAINTAINED AS PHYSICAL;
EDIT DATABASE 'VERADBPRD_DR' SET PROPERTY StaticConnectIdentifier =
'(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=dataveraproddbdr.dataveralabs.local)(PORT=1610))(CONNECT_DATA=(SERVICE_NAME=VERADBPRD_DR_DGMGRL)(INSTANCE_NAME=VERADBPRD_DR)(SERVER=DEDICATED)))';
ENABLE CONFIGURATION;DBA note Once Broker owns the configuration, avoid manually duplicating LOG_ARCHIVE_CONFIG / LOG_ARCHIVE_DEST_2 — Broker populates these itself.
Validate transport & apply
-- PRIMARY
SELECT DEST_ID, STATUS, DATABASE_MODE, RECOVERY_MODE,
GAP_STATUS, ERROR
FROM V$ARCHIVE_DEST_STATUS
WHERE DEST_ID=2;Expected result STATUS=VALID, DATABASE_MODE=MOUNTED-STANDBY, RECOVERY_MODE=MANAGED REAL TIME APPLY, GAP_STATUS=NO GAP, ERROR blank.
-- STANDBY
SELECT NAME, VALUE, UNIT
FROM V$DATAGUARD_STATS
WHERE NAME IN ('transport lag','apply lag','apply finish time');Expected result Transport and apply lag are zero or within your approved operational threshold.
SHOW CONFIGURATION;
SHOW DATABASE 'VERADBPRD';
SHOW DATABASE 'VERADBPRD_DR';Expected result: Configuration Status: SUCCESS, Fast-Start Failover: Disabled.
Planned switchover test
⚠ Production impact: Run only during an approved change window. This changes which database is primary and briefly interrupts write availability. Confirm zero/acceptable lag and a SUCCESS Broker status before proceeding. Please note: Need to execute these commands from the dgmgrl utility
SHOW CONFIGURATION;
SHOW DATABASE 'VERADBPRD';
SHOW DATABASE 'VERADBPRD_DR';
-- Primary
SELECT NAME, OPEN_MODE, DATABASE_ROLE, SWITCHOVER_STATUS
FROM V$DATABASE;
SWITCHOVER TO 'VERADBPRD_DR';Expected result VERADBPRD_DR becomes PRIMARY, VERADBPRD becomes PHYSICAL STANDBY.
Rollback / switch back:
SWITCHOVER TO 'VERADBPRD';
SHOW CONFIGURATION;Expected result VERADBPRD is PRIMARY again, VERADBPRD_DR is PHYSICAL STANDBY, Broker returns SUCCESS.
Troubleshooting
ORA-16789 — Standby redo logs configured incorrectly
The reference build initially had four SRLs with THREAD#=0. Broker reported ORA-16789 even though transport was functioning. Fix: recreate SRLs as Thread 1 on both primary and standby.
SELECT GROUP#, THREAD#, BYTES/1024/1024 SIZE_MB, STATUS
FROM V$STANDBY_LOG
ORDER BY GROUP#;ORA-01156 — recovery or flashback in progress
Dropping an SRL while managed recovery is running can fail with ORA-01156. Stop apply through Broker first, and only drop a confirmed UNASSIGNED SRL.
EDIT DATABASE 'VERADBPRD_DR' SET STATE='APPLY-OFF';TNS-03505 — Failed to resolve name
Confirm the environment and TNS entries are actually what the session is using:
echo $ORACLE_HOME
echo $TNS_ADMIN
which tnsping
grep -n -A12 -B2 "VERADBPRD_DR_DGMGRL" $TNS_ADMIN/tnsnames.ora
tnsping VERADBPRD_DR_DGMGRLProduction checklist
- DB_NAME matches between primary and standby
- DB_UNIQUE_NAME values are unique
- Primary is ARCHIVELOG and FORCE_LOGGING
- TNS connectivity works in both directions
- Standby static Broker service is configured
- RMAN Active Duplicate completes successfully
- Standby is PHYSICAL STANDBY and MOUNTED
- Primary and standby each have 6 × 10 GB SRLs on Thread 1
- Broker configuration files are assigned to ASM
- DG_BROKER_START=TRUE on both databases
- Broker configuration is enabled
- Redo transport is VALID, GAP_STATUS=NO GAP
- Real-time apply is active; transport/apply lag within threshold
- Fast-Start Failover is Disabled
- Planned switchover and switchback tested (if approved)
Conclusion
This gives you a Broker-managed Oracle 19c physical standby with asynchronous redo transport and real-time apply, supporting controlled manual switchover and switchback without enabling automatic failover. Keep FSFO disabled unless your environment has a tested observer setup and an approved reason to automate role transitions.