Oracle Data Guard Configuration: A Step-by-Step Guide for Production DBAs

Configuring Oracle Data Guard doesn’t have to be a week-long project. Here’s the practical sequence we’ve used on hundreds of production systems — primary setup, standby creation, observer configuration, and the switchover runbook.


Why Data Guard Is Still the Baseline in 2026

Every Oracle environment that cares about its data has Data Guard in the picture — or should. Whether you’re running on-premises Exadata, Oracle Cloud Infrastructure, or a hybrid setup, Data Guard is the most battle-tested data protection mechanism Oracle has. It predates most of the cloud-native alternatives and remains the right choice when you need:

  • Zero or near-zero RPO on your primary database
  • Automatic or manual failover without data loss
  • A synchronized standby you can open read-only for reporting or backups
  • Protection modes that match your business requirements (Maximum Performance vs. Maximum Availability vs. Maximum Protection)

We’ve configured Data Guard on systems ranging from 500GB single-instance to 40TB RAC clusters. The sequence is the same every time. This guide walks through it exactly as we do it in production.

Prerequisites: What You Need Before You Start

Free · 2 Minutes
How healthy is your database, really?
Get your free database health score — spot risks before they become incidents.
Get my health score

Before touching anything, confirm these are in place on both the primary and standby hosts:

  • Oracle software installed and running the same release/patch level on both servers
  • Oracle Net listener configured on both hosts — lsnrctl status returns the expected service name
  • Password file exists on the primary (orapw<ORACLE_SID>) — you’ll copy this to the standby
  • Oracle Managed Files (OMF) enabled or you’re prepared to specify full filenames on all file creation commands
  • Flashback Database enabled on the primary — this makes DG Broker switchovers dramatically cleaner and is required for some configurations
  • Archive log mode enabledSELECT log_mode FROM v\$database; must return ARCHIVELOG
  • Standby redo logs sized to match your primary online redo logs — if you don’t have them, add them before enabling Data Guard
  • Firewall ports open between primary and standby on TCP 1521 (or your custom listener port)
  • Tnsnames.ora entries exist on both hosts for the primary and standby aliases

Step 1: Configure the Primary Database for Redo Transport

Start on the primary. Set the Data Guard configuration parameters via ALTER SYSTEM. These are persistent and survive restarts.

-- Force log shipping (mandatory)
ALTER SYSTEM SET log_archive_dest_1=‘LOCATION=USE_DB_RECOVERY_FILE_DEST VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=PRIMARY’;

-- Destination for redo received by standby
ALTER SYSTEM SET log_archive_dest_2=‘SERVICE=STANDBYASYNC VALIDFOR=(ONLINE_LOGFILE,PRIMARY_ROLE) DB_UNIQUE_NAME=STANDBY’;

-- Set the DB unique name (required for DG Broker)
ALTER SYSTEM SET db_unique_name=‘PRIMARY’ SCOPE=BOTH;

-- Specify which roles can use each destination
ALTER SYSTEM SET log_archive_dest_state_1=‘ENABLE’;
ALTER SYSTEM SET log_archive_dest_state_2=‘ENABLE’;

The STANDBYASYNC in log_archive_dest_2 means asynchronous redo transport — the primary doesn’t wait for the standby to acknowledge. This is the right setting for Maximum Performance mode (the default). For Maximum Availability, you’d use STANDBYSYNC and add AFFIRM.

Step 2: Create the Standby Database

There are two ways to create the standby: RMAN duplicate from active database, or restore from a backup. The RMAN duplicate method is faster and is what we use in most scenarios.

Option A: RMAN Duplicate (Preferred)

On the standby host, create the necessary directories and set up a minimal init.ora for the standby. Then connect RMAN to both the primary (as target) and the standby (as auxiliary):

rman target sys/password@PRIMARY auxiliary sys/password@STANDBY

DUPLICATE TARGET DATABASE
  FOR STANDBY
  FROM ACTIVE DATABASE
  DORECOVER
  SPFILE
    SET db_unique_name=‘STANDBY’
    SET log_archive_dest_1=‘LOCATION=USE_DB_RECOVERY_FILE_DEST VALIDFOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=STANDBY’
    SET log_archive_dest_2=‘SERVICE=PRIMARYASYNC VALIDFOR=(ONLINE_LOGFILE,STANDBY_ROLE) DB_UNIQUE_NAME=PRIMARY’
    SET fal_server=‘PRIMARY’
    SET fal_client=‘STANDBY’
    SET standby_file_management=‘AUTO’
  NOFILENAMECHECK;

The DORECOVER clause tells RMAN to continue applying archived logs until the standby is in sync with the primary. This can take a while on large databases — budget 30–90 minutes depending on size and network speed.

Option B: Restore from Backup (When Duplicate Won’t Work)

If the standby can’t reach the primary over the network (rare but happens in strict network segmentation scenarios), take a backup on primary and ship it to standby:

-- On primary: full backup plus control file for standby
RMAN> BACKUP FORMAT ‘/backup/%U’ DATABASE PLUS ARCHIVELOG;
RMAN> BACKUP CURRENT CONTROLFILE FOR STANDBY FORMAT ‘/backup/standby_control.ctl’;

Copy everything to the standby, restore the control file, then restore and recover the database. This method works in air-gapped or strict-LAN-only topologies.

Step 3: Create Standby Redo Logs on Both Sites

Standby redo logs (SRLs) are the receiving mechanism for redo data on the standby. Without them, the standby can only recover — it can’t apply in real-time. For any production Data Guard configuration, you want real-time apply.

-- On primary: one SRL per thread, matching the size of your online redo logs
ALTER DATABASE ADD STANDBY LOGFILE THREAD 1 (‘/u01/oradata/PRIMARY/srl01.log’) SIZE 256M;
ALTER DATABASE ADD STANDBY LOGFILE THREAD 1 (‘/u01/oradata/PRIMARY/srl02.log’) SIZE 256M;
ALTER DATABASE ADD STANDBY LOGFILE THREAD 1 (‘/u01/oradata/PRIMARY/srl03.log’) SIZE 256M;

-- On standby: same configuration
ALTER DATABASE ADD STANDBY LOGFILE THREAD 1 (‘/u01/oradata/STANDBY/srl01.log’) SIZE 256M;
ALTER DATABASE ADD STANDBY LOGFILE THREAD 1 (‘/u01/oradata/STANDBY/srl02.log’) SIZE 256M;
ALTER DATABASE ADD STANDBY LOGFILE THREAD 1 (‘/u01/oradata/STANDBY/srl03.log’) SIZE 256M;

-- If running RAC, add SRLs for each thread on each instance

Verify your SRL count: SELECT GROUP#, THREAD#, BYTES FROM v\$standby_log ORDER BY THREAD#, GROUP#;

Step 4: Start the Standby’s Apply Process

On the standby, put the database in mount mode and start Redo Apply:

-- Ensure standby is in mount state
SHUTDOWN IMMEDIATE;
STARTUP NOMOUNT;
ALTER DATABASE MOUNT STANDBY DATABASE;

-- Real-time apply (recommended for production)
ALTER DATABASE RECOVER MANAGED STANDBY DATABASE USING CURRENT LOGFILE DISCONNECT FROM SESSION;

-- Or deferred apply (for maintenance windows):
-- ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT FROM SESSION;

The USING CURRENT LOGFILE clause enables real-time apply — redo is applied as it arrives, not just during recovery intervals. DISCONNECT FROM SESSION runs the apply in the background.

Monitor apply progress:

SELECT SEQUENCE#, APPLIED, ARCHIVE_TIME, COMPLETION_TIME
FROM V\$ARCHIVED_LOG
WHERE APPLIED=‘YES’
ORDER BY SEQUENCE# DESC
FETCH FIRST 10 ROWS ONLY;

Step 5: Configure the Data Guard Broker (DGB)

The DG Broker is Oracle’s management interface for Data Guard. Without it, you’re managing configuration via static init.ora parameters. With it, you get a centralized CLI, automatic failover, and Far Sync support. Always use the broker in production.

Enable the Broker on Both Sites

-- On primary
ALTER SYSTEM SET dg_broker_start=TRUE SCOPE=BOTH;

-- On standby
ALTER SYSTEM SET dg_broker_start=TRUE SCOPE=BOTH;

Create the Broker Configuration

dgmgrl sys/password@PRIMARY

CREATE CONFIGURATION ‘PROD_DG’ AS PRIMARY DATABASE IS ‘PRIMARY’
  CONNECT IDENTIFIER IS ‘PRIMARY’;

ADD DATABASE ‘STANDBY’ AS CONNECT IDENTIFIER IS ‘STANDBY’
  MAINTAINED AS PHYSICAL;

ENABLE CONFIGURATION;

Validate everything is healthy:

DGMGRL> SHOW CONFIGURATION

Configuration - PROD_DG
  Protection Mode: MaxPerformance
  Databases:
    PRIMARY   - Primary database
    STANDBY   - Physical standby database
  Fast-Start Failover: Disabled

Configuration Status:
  SUCCESS

Set the Protection Mode

By default, DG Broker creates configurations in Maximum Performance mode. If you need Maximum Availability:

DGMGRL> EDIT DATABASE ‘PRIMARY’ SET PROPERTY LogXptMode=Sync;
DGMGRL> EDIT DATABASE ‘STANDBY’ SET PROPERTY LogXptMode=Sync;
DGMGRL> EDIT CONFIGURATION SET PROTECTION MODE AS MAXAVAILABILITY;

Step 6: Test the Configuration End-to-End

Before calling this done, test three things:

1. Verify Redo Shipping

-- On primary: force a log switch
ALTER SYSTEM SWITCH LOGFILE;

-- On standby: verify the sequence arrived
SELECT SEQUENCE#, APPLIED, ARCHIVE_TIME
FROM V\$ARCHIVED_LOG
ORDER BY SEQUENCE# DESC
FETCH FIRST 5 ROWS ONLY;

2. Verify the Standby Is Receiving and Applying

-- On standby: check managed recovery is running
SELECT PROCESS, STATUS, SEQUENCE# FROM V\$MANAGED_STANDBY;

-- Should show MRP0 with APPLYING_LOG, RFS with RECEIVE, LNS with SENDING

3. Check the Data Guard Status View

-- On primary
SELECT MESSAGE, TIMESTAMP FROM v\$dataguard_status
WHERE TIMESTAMP > SYSDATE-1
ORDER BY TIMESTAMP DESC;

Step 7: Run Your First Switchover (Do This Before You Need It)

A switchover is a planned role reversal — primary becomes standby, standby becomes primary. It’s the safe way to test your configuration. Do it in a maintenance window. It’s reversible if something goes wrong.

dgmgrl sys/password@PRIMARY

-- Validate both databases are ready
VALIDATE DATABASE ‘STANDBY’;

-- Initiate switchover (primary becomes standby)
SWITCHOVER TO ‘STANDBY’;

The command verifies the standby is ready, converts the primary to a standby, then converts the standby to a primary. Total time for a well-configured system: 60–90 seconds.

Common Issues We See in Practice

Standby Falls Behind — Sequence Gap

If the standby is more than 10 sequences behind, check: (1) is the archive log destination full on the standby? (2) is network throughput adequate? (3) is the standby in read-only mode with apply running?

-- On standby: stop apply, ship missing logs, restart
ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;
-- SCP missing logs to /u01/archive/
ALTER DATABASE REGISTER LOGFILE ‘/u01/archive/arc_SEQ_123_ABC.log’;
ALTER DATABASE RECOVER MANAGED STANDBY DATABASE USING CURRENT LOGFILE DISCONNECT FROM SESSION;

ORA-16009: Remote Archive Log Destination Is Invalid

This usually means the db_unique_name on one side doesn’t match the other. Check v\$archive_dest on both sides — DB_UNIQUE_NAME is case-sensitive on some platforms.

DG Broker Won’t Connect

Verify the GLOBAL_DBNAME in the listener.ora on the remote side includes the _DGMGRL suffix:

SID_LIST_LISTENER =
  (SID_LIST =
    (SID_DESC =
      (GLOBAL_DBNAME=STANDBY_DGMGRL)  -- required for DG Broker
      (ORACLE_HOME=/u01/oracle/19c)
      (SID_NAME=STANDBY)
    )
  )

What’s Next After Setup

Now that Data Guard is running, a few things we put in place immediately after configuration:

  • Far Sync Instance: If you need Maximum Protection mode without geographically limiting your primary, add a Far Sync instance. It receives redo synchronously from the primary and forwards it asynchronously to standbys — zero data loss protection without the latency constraint.
  • Fast-Start Failover (FSFO): Enable it for automatic failover within a defined timeout. Combined with an Oracle Observer on a third host, FSFO gives you RTO under 30 seconds.
  • Monitoring: Add V\$DATAGUARD_STATS to your monitoring. We’re happy to audit your Data Guard setup as part of a Database Health Assessment.

Data Guard configuration done right is a one-time investment that pays dividends every day your primary is healthy. When something does go wrong, the difference between a tested configuration and an untested one is measured in hours of downtime.

Free · Takes 2 Minutes

Get your free database health score

Find out exactly where your database is vulnerable before it causes an incident. 30+ years of DBA expertise, distilled into a single assessment.

Back to all posts