In this article, we will create a data guard standby database using RMAN active database. For this, we need to configure both servers, primary and secondary, with the listener.ora and tnsnames.ora files, ensuring cross-connections between the servers. This setup allows the primary server to access the database on the secondary server and vice versa.
For primary database follow the example below:
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = oraserver)(PORT = 1521))
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
)
)
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(SID_NAME = cdb19c)
(ORACLE_HOME = /u01/app/oracle/product/19.0.0/db)
(GLOBAL_DBNAME = cdb19c)
)
(SID_DESC =
(SID_NAME = cdb19c)
(ORACLE_HOME = /u01/app/oracle/product/19.0.0/db)
(GLOBAL_DBNAME = cdb19c_dgmgrl)
)
)
For Data Guard server, follow the example below:
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = oraserverdg)(PORT = 1521))
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
)
)
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(SID_NAME = cdb19cdg)
(ORACLE_HOME = /u01/app/oracle/product/19.0.0/db)
(GLOBAL_DBNAME = cdb19cdg)
)
(SID_DESC =
(SID_NAME = cdb19cdg)
(ORACLE_HOME = /u01/app/oracle/product/19.0.0/db)
(GLOBAL_DBNAME = cdb19cdg_dgmgrl)
)
)
Reload both listeners if they are already started:
[oracle@oraserver:cdb19c admin]$ lsnrctl reload
[oracle@oraserver:cdb19c admin]$ lsnrctl status
LSNRCTL for Linux: Version 19.0.0.0.0 - Production on 02-APR-2025 13:56:55
Copyright (c) 1991, 2023, Oracle. All rights reserved.
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=oraserver)(PORT=1521)))
STATUS of the LISTENER
------------------------
Alias LISTENER
Version TNSLSNR for Linux: Version 19.0.0.0.0 - Production
Start Date 02-APR-2025 13:26:09
Uptime 0 days 0 hr. 30 min. 46 sec
Trace Level off
Security ON: Local OS Authentication
SNMP OFF
Listener Parameter File /u01/app/oracle/product/19.0.0/db/network/admin/listener.ora
Listener Log File /u01/app/oracle/diag/tnslsnr/oraserver/listener/alert/log.xml
Listening Endpoints Summary...
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=oraserver)(PORT=1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
Services Summary...
Service "cdb19c" has 1 instance(s).
Instance "cdb19c", status UNKNOWN, has 1 handler(s) for this service...
Service "cdb19c_dgmgrl" has 1 instance(s).
Instance "cdb19c", status UNKNOWN, has 1 handler(s) for this service...
The command completed successfully
And for Standby:
[oracle@oraserverdg:cdb19cdg admin]$ lsnrctl reload
[oracle@oraserverdg:cdb19cdg admin]$ lsnrctl status
LSNRCTL for Linux: Version 19.0.0.0.0 - Production on 02-APR-2025 13:32:07
Copyright (c) 1991, 2023, Oracle. All rights reserved.
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=oraserverdg)(PORT=1521)))
STATUS of the LISTENER
------------------------
Alias LISTENER
Version TNSLSNR for Linux: Version 19.0.0.0.0 - Production
Start Date 02-APR-2025 13:25:48
Uptime 0 days 0 hr. 6 min. 19 sec
Trace Level off
Security ON: Local OS Authentication
SNMP OFF
Listener Parameter File /u01/app/oracle/product/19.0.0/db/network/admin/listener.ora
Listener Log File /u01/app/oracle/diag/tnslsnr/oraserverdg/listener/alert/log.xml
Listening Endpoints Summary...
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=oraserverdg)(PORT=1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
Services Summary...
Service "cdb19cdg" has 1 instance(s).
Instance "cdb19cdg", status UNKNOWN, has 1 handler(s) for this service...
Service "cdb19cdg_dgmgrl" has 1 instance(s).
Instance "cdb19cdg", status UNKNOWN, has 1 handler(s) for this service...
The command completed successfully
Now, add TNS strings connection for both servers and databases. Use the same for primary and data guard:
CDB19C =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = oraserver)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = cdb19c)
)
)
CDB19CDG =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = oraserverdg)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = cdb19cdg)
(UR = A)
)
)
Note the UR parameter in the standby connection string. Since the standby will be in NOMOUNT mode, this parameter will allow us to access the secondary database even in this state.
Copy password file from primary to data guard and change the file name, to match the match the standby database name:
[oracle@oraserver:cdb19c admin]$ scp /u01/app/oracle/product/19.0.0/db/dbs/orapwcdb19c oraserverdg:/u01/app/oracle/product/19.0.0/db/dbs/orapwcdb19cdg
From primary database, create a pfile parameter file and copy to data guard database server:
[oracle@oraserver:cdb19c ~]$ sqlplus
SQL*Plus: Release 19.0.0.0.0 - Production on Wed Apr 2 13:15:12 2025
Version 19.19.0.0.0
Copyright (c) 1982, 2023, Oracle. All rights reserved.
Enter user-name: /as sysdba
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.19.0.0.0
SQL> create pfile='/tmp/initcdb19cdg.ora' from spfile;
File created.
SQL>
[oracle@oraserver:cdb19c ~]$ scp /tmp/initcdb19cdg.ora oraserverdg:/u01/app/oracle/product/19.0.0/db/dbs
If there is a different path between the servers, we must modify it using the db_file_name_convert and log_file_name_convert parameters, otherwise, the file should remain the same as in production. We must add the standby_file_management parameter and set it to AUTO. This is used to automatically create datafiles.
Also, you need to change db_unique_name parameter for your new data guard database name.
After these configurations, we should start the standby database in nomount mode using the created pfile.
[oracle@oraserverdg:cdb19cdg ~]$ echo $ORACLE_SID
cdb19cdg
[oracle@oraserverdg:cdb19cdg ~]$ sqlplus "/as sysdba"
SQL*Plus: Release 19.0.0.0.0 - Production on Sun Jul 13 17:13:10 2025
Version 19.19.0.0.0
Copyright (c) 1982, 2023, Oracle. All rights reserved.
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.19.0.0.0
Connected to an idle instance.
SQL> startup nomount pfile=/u01/app/oracle/product/19.0.0/db/dbs/initcdb19cdg.ora
ORACLE instance started.
Total System Global Area 943669248 bytes
Fixed Size 2234000 bytes
Variable Size 289409392 bytes
Database Buffers 645922816 bytes
Redo Buffers 6103040 bytes
SQL> create spfile from pfile;
SQL> shutdown immediate;
SQL> startup nomount
SQL> exit
After starting the database, we can connect via RMAN to the target/source and auxiliary/destination databases through the listener and execute the DUPLICATE command.
[oracle@oraserverdg:cdb19cdg ~]$ rman target sys/oracle@cdb19c auxiliary sys/oracle@cdb19cdg
Recovery Manager: Release 19.0.0.0.0 - Production on Sun Jul 13 17:13:10 2025
Copyright (c) 1982, 2023, Oracle and/or its affiliates. All rights reserved.
connected to target database: CDB19C (DBID=376455823)
connected to auxiliary database: CDB19CDG (not mounted)
RMAN> duplicate target database for standby from active database dorecover nofilenamecheck;
Let’s see the results:
[oracle@oraserverdg:cdb19cdg ~]$ ps -ef |grep pmon
oracle 2772 1 0 11:16 ? 00:00:00 ora_pmon_cdb19cdg
oracle 3208 2686 0 11:32 pts/0 00:00:00 grep pmon
[oracle@oraserverdg:cdb19cdg ~]$ sqlplus "/as sysdba"
SQL*Plus: Release 19.0.0.0.0 - Production on Sun Jul 13 17:13:10 2025
Version 19.19.0.0.0
Copyright (c) 1982, 2023, Oracle. All rights reserved.
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.19.0.0.0
SQL> select status from v$instance;
STATUS
————
MOUNTED
SQL> alter database open read only;
Database altered.
SQL>
Now, let’s set some parameters before starting broker. In both databases, we need modify the parameters below:
[oracle@oraserver:cdb19c ~]$ sqlplus "/as sysdba"
SQL*Plus: Release 19.0.0.0.0 - Production on Sun Jul 13 17:13:10 2025
Version 19.19.0.0.0
Copyright (c) 1982, 2023, Oracle. All rights reserved.
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.19.0.0.0
SQL> ALTER SYSTEM SET dg_broker_start=true;
Database altered.
SQL> ALTER SYSTEM set REMOTE_LOGIN_PASSWORDFILE=EXCLUSIVE scope = both;
Database altered.
SQL> ALTER SYSTEM set STANDBY_FILE_MANAGEMENT=AUTO scope = both;
Database altered.
SQL> alter database flashback on;
Database altered.
SQL>
Primary will need to send redo data to data guard and to do this, it use standby redo log files. If you have 3 log files on primary, you will need 3 standby log files, plus 1 at least, that is, 4 standby log files or more and is mandatory they have the same size of on line primary log files.
Lets create 4 standby log files:
SQL> ALTER DATABASE ADD STANDBY LOGFILE thread 1 ('/u02/oradata/CDB19C/standby_redo01.log') SIZE 200M;
Database altered.
SQL> ALTER DATABASE ADD STANDBY LOGFILE thread 1 ('/u02/oradata/CDB19C/standby_redo02.log') SIZE 200M;
Database altered.
SQL> ALTER DATABASE ADD STANDBY LOGFILE thread 1 ('/u02/oradata/CDB19C/standby_redo03.log') SIZE 200M;
Database altered.
SQL> ALTER DATABASE ADD STANDBY LOGFILE thread 1 ('/u02/oradata/CDB19C/standby_redo04.log') SIZE 200M;
Database altered.
SQL> select member, type from v$logfile;
MEMBER TYPE
----------------------------------------- -------
/u02/oradata/CDB19C/redo03.log ONLINE
/u02/oradata/CDB19C/redo02.log ONLINE
/u02/oradata/CDB19C/redo01.log ONLINE
/u02/oradata/CDB19C/standby_redo01.log STANDBY
/u02/oradata/CDB19C/standby_redo02.log STANDBY
/u02/oradata/CDB19C/standby_redo03.log STANDBY
/u02/oradata/CDB19C/standby_redo04.log STANDBY
7 rows selected.
SQL>
On dataguard you also need to create standby log files, the same quantity and size you created on primary. Take care to modify destination location:
SQL> ALTER DATABASE ADD STANDBY LOGFILE thread 1 ('/u02/oradata/CDB19CDG/standby_redo01.log') SIZE 200M;
Database altered.
SQL> ALTER DATABASE ADD STANDBY LOGFILE thread 1 ('/u02/oradata/CDB19CDG/standby_redo02.log') SIZE 200M;
Database altered.
SQL> ALTER DATABASE ADD STANDBY LOGFILE thread 1 ('/u02/oradata/CDB19CDG/standby_redo03.log') SIZE 200M;
Database altered.
SQL> ALTER DATABASE ADD STANDBY LOGFILE thread 1 ('/u02/oradata/CDB19CDG/standby_redo04.log') SIZE 200M;
Database altered.
SQL> select member, type from v$logfile;
MEMBER TYPE
--------------------------------------------- -------
/u02/oradata/CDB19CDG/redo03.log ONLINE
/u02/oradata/CDB19CDG/redo02.log ONLINE
/u02/oradata/CDB19CDG/redo01.log ONLINE
/u02/oradata/CDB19CDG/standby_redo01.log STANDBY
/u02/oradata/CDB19CDG/standby_redo02.log STANDBY
/u02/oradata/CDB19CDG/standby_redo03.log STANDBY
/u02/oradata/CDB19CDG/standby_redo04.log STANDBY
7 rows selected.
SQL>
On broker manager, lets create configuration broker:
$ dgmgrl sys/oracle@cdb19c
DGMGRL for Linux: Release 19.0.0.0.0 - Production on Tue Feb 26 22:39:33 2018
Version 19.2.0.0.0
Copyright (c) 1982, 2019, Oracle and/or its affiliates. All rights reserved.
Welcome to DGMGRL, type "help" for information.
Connected as SYSDBA.
DGMGRL> CREATE CONFIGURATION dg_config AS PRIMARY DATABASE IS cdb19c CONNECT IDENTIFIER IS cdb19c;
Configuration "dg_config" created with primary database "cdb19c"
DGMGRL> ADD DATABASE cdb19cdg AS CONNECT IDENTIFIER IS cdb19cdg MAINTAINED AS PHYSICAL;
Database "cdb19cdg" added
DGMGRL> edit database cdb19c set property StaticConnectIdentifier="oraserver:1521/cdb19c_dgmgrl";
Property "StaticConnectIdentifier" updated
DGMGRL> edit database cdb19cdg set property StaticConnectIdentifier="oraserverdg:1521/cdb19cdg_dgmgrl";
Property "StaticConnectIdentifier" updated
DGMGRL> EDIT DATABASE cdb19c SET PROPERTY 'LogXptMode'='SYNC';
Property "LogXptMode" updated
DGMGRL> EDIT DATABASE cdb19cdg SET PROPERTY 'LogXptMode'='SYNC';
Property "LogXptMode" updated
DGMGRL> ENABLE CONFIGURATION;
Enabled.
At this moment, we can do final checks. First, lets check flashback on both databases:
SQL> SELECT FLASHBACK_ON FROM V$DATABASE;
FLASHBACK_ON
------------------
NO
SQL>
If this is disabled, stop applying and change the status. On broker manager:
DGMGRL> EDIT DATABASE cdb19cdg SET STATE='APPLY-OFF';
Succeeded.
Now, on sqlplus database:
SQL> alter database flashback on;
Database altered.
SQL> SELECT FLASHBACK_ON FROM V$DATABASE;
FLASHBACK_ON
------------------
YES
SQL>
Back applying state to ON.
DGMGRL> EDIT DATABASE cdb19cdg SET STATE='APPLY-ON';
Succeeded.
DGMGRL>
Lets check apply status on data guard database:
SELECT process, status FROM v$managed_standby;
PROCESS STATUS
--------- ------------
ARCH CLOSING
DGRD ALLOCATED
DGRD ALLOCATED
ARCH CLOSING
ARCH CONNECTED
ARCH CONNECTED
MRP0 APPLYING_LOG
RFS IDLE
RFS IDLE
RFS IDLE
RFS IDLE
PROCESS STATUS
--------- ------------
RFS IDLE
RFS IDLE
RFS IDLE
Look for a process named MRP (Managed Recovery Process) and its status, which should indicate “APPLYING_LOG” for real-time apply.
To finish, we can check configuration. On dgmgrl:
DGMGRL> show configuration;
Configuration - dg_config
Protection Mode: MaxPerformance
Members:
cdb19c - Primary database
cdb19cdg - Physical standby database
Fast-Start Failover: Disabled
Configuration Status:
SUCCESS (status updated 8 seconds ago)
Thats all for now!!!