Oracle Data Guard is the industry standard for Oracle high availability — a standby database that stays synchronized with production and can take over in minutes. But the switchover and failover procedures trip up even experienced DBAs because the steps differ, the order matters, and a mistake during failover can lose data or leave both databases in an unusable state. This article covers both procedures end to end.

Switchover vs Failover — Know the Difference

Switchover — planned role reversal. Both databases are available, no data loss, the original primary can come back as a standby. Use this for planned maintenance, DR testing, or datacenter migrations.

Failover — unplanned. The primary is unavailable (crashed, network isolated, datacenter down). The standby becomes the new primary. The old primary cannot rejoin without being reinstated. There may be data loss depending on your protection mode.

-- Check current Data Guard configuration
SELECT database_role, db_unique_name, open_mode, protection_mode
FROM v$database;

-- Check standby lag
SELECT name, value, datum_time
FROM v$dataguard_stats
WHERE name IN ('transport lag', 'apply lag');

Protection Modes

Your protection mode determines the data loss risk during failover:

-- Check current protection mode
SELECT protection_mode, protection_level FROM v$database;

-- Change protection mode (requires broker or manual steps)
ALTER DATABASE SET STANDBY DATABASE TO MAXIMIZE AVAILABILITY;

Pre-Switchover Checks

Always verify the configuration is healthy before a planned switchover:

-- On primary: check standby is synchronized
SELECT dest_id, status, target, archiver, schedule,
       destination, error
FROM v$archive_dest
WHERE target = 'STANDBY'
  AND status != 'INACTIVE';

-- Check apply lag is zero or near zero
SELECT name, value FROM v$dataguard_stats
WHERE name IN ('apply lag', 'transport lag');

-- Check for any gaps
SELECT * FROM v$archive_gap;

-- Verify standby is in managed recovery
-- (Run this on standby)
SELECT process, status, sequence#
FROM v$managed_standby
WHERE process IN ('MRP0','RFS')
ORDER BY process;

Switchover Procedure

Step 1: Convert primary to standby

-- On PRIMARY: initiate switchover
ALTER DATABASE COMMIT TO SWITCHOVER TO STANDBY WITH SESSION SHUTDOWN;

-- Wait for it to complete (can take 1-5 minutes depending on active sessions)
-- Monitor in alert log: grep "SWITCHOVER" $ORACLE_BASE/diag/rdbms/*/trace/alert*.log

-- Verify primary is now in standby role
SELECT switchover_status FROM v$database;
-- Should show: TO PRIMARY or SESSIONS ACTIVE (if still processing)

Step 2: Convert standby to primary

-- On STANDBY: convert to primary
ALTER DATABASE COMMIT TO SWITCHOVER TO PRIMARY WITH SESSION SHUTDOWN;

-- Open the new primary
ALTER DATABASE OPEN;

-- Verify role
SELECT database_role, open_mode FROM v$database;
-- Should show: PRIMARY, READ WRITE

Step 3: Start managed recovery on new standby

-- On the OLD PRIMARY (now standby): start recovery
ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT FROM SESSION;

-- Or with real-time apply (recommended)
ALTER DATABASE RECOVER MANAGED STANDBY DATABASE USING CURRENT LOGFILE DISCONNECT;

-- Verify recovery is running
SELECT process, status, sequence# FROM v$managed_standby;

Step 4: Update connection strings

Update your application connection strings, load balancers, and TNS entries to point to the new primary's host. For EBS environments, run AutoConfig on all tiers pointing to the new primary.

Failover Procedure

Failover is used when the primary is unavailable. Work quickly but carefully — mistakes here can require complete standby rebuild.

Step 1: Confirm primary is truly down

Before failing over, confirm the primary is actually unavailable — not just a network partition where the primary is still running. A split-brain scenario (both databases thinking they're primary) is far worse than a brief outage.

# Try to connect to primary from application server
tnsping PRIMARY_TNS_ALIAS

# Try SSH to primary host
ssh oracle@primary-host "sqlplus / as sysdba <<< 'SELECT status FROM v\$instance;'"

Only proceed with failover if primary is confirmed unreachable.

Step 2: Check standby apply status

-- On STANDBY: check how far apply has progressed
SELECT MAX(sequence#) applied_seq
FROM v$archived_log
WHERE applied = 'YES'
  AND standby_dest = 'NO';

-- Check for any unapplied logs
SELECT sequence#, applied FROM v$archived_log
WHERE applied = 'NO'
  AND standby_dest = 'NO'
ORDER BY sequence#;

Step 3: Apply any remaining redo (if accessible)

If the primary's redo logs are accessible via shared storage or backup:

-- Cancel managed recovery temporarily
ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;

-- Apply any remaining archived logs manually
ALTER DATABASE RECOVER AUTOMATIC STANDBY DATABASE
  UNTIL CANCEL USING BACKUP CONTROLFILE;
-- Type CANCEL when no more logs to apply

-- Or register and apply specific log files
ALTER DATABASE REGISTER LOGFILE '/path/to/archived/log';

Step 4: Activate the standby

-- OPTION A: Activate with possible data loss (faster)
ALTER DATABASE ACTIVATE STANDBY DATABASE;

-- OPTION B: Finish recovery then activate (safer, use if logs accessible)
ALTER DATABASE RECOVER MANAGED STANDBY DATABASE FINISH;
ALTER DATABASE ACTIVATE STANDBY DATABASE;

-- Open the new primary
SHUTDOWN IMMEDIATE;
STARTUP;

-- Verify it's open as primary
SELECT database_role, open_mode FROM v$database;

Step 5: Open with RESETLOGS

After activation, the database opens with a new incarnation:

ALTER DATABASE OPEN RESETLOGS;

This is permanent — the old primary cannot rejoin without reinstatement.

Post-Failover: Reinstating the Old Primary

Once the old primary comes back online, it cannot simply resume as a standby — it needs to be reinstated or rebuilt.

Option A: Flashback reinstatement (if Flashback Database was enabled)

-- On old primary (after it comes back up):
STARTUP MOUNT;

-- Flashback to before the failover
FLASHBACK DATABASE TO SCN <scn_at_failover>;

-- Convert to standby
ALTER DATABASE CONVERT TO PHYSICAL STANDBY;
SHUTDOWN IMMEDIATE;
STARTUP MOUNT;

-- Start managed recovery
ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT;

Option B: RMAN duplicate from new primary

If Flashback wasn't enabled, rebuild the standby from scratch:

# From the standby server, duplicate from the new primary
rman target sys/<pwd>@new_primary auxiliary sys/<pwd>@old_primary_as_standby

DUPLICATE TARGET DATABASE FOR STANDBY FROM ACTIVE DATABASE
  DORECOVER
  SPFILE
    SET db_unique_name='OLD_PRIMARY_UNIQUE_NAME'
    SET log_archive_dest_2='SERVICE=new_primary LGWR ASYNC VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=new_primary'
  NOFILENAMECHECK;

Data Guard Broker (Recommended)

The above manual procedures are error-prone. Oracle Data Guard Broker automates switchover, failover, and reinstatement through a single command:

# Connect to broker
dgmgrl sys/<pwd>@primary

# Verify configuration
DGMGRL> show configuration;
DGMGRL> show database verbose primary_db;

# Planned switchover (one command)
DGMGRL> switchover to standby_db;

# Fast-start failover (if configured)
DGMGRL> failover to standby_db;

Broker validates the configuration, performs pre-checks, executes the role change, and updates all members automatically.

Common Failure Points

ORA-16139: media recovery required — standby has unapplied logs. Cancel recovery, apply remaining logs, retry.

ORA-16820: fast-start failover target standby database is no longer synchronized — apply lag exceeded the FastStartFailoverThreshold. Increase the threshold or fix the lag.

Switchover status shows SESSIONS ACTIVE — active user sessions are blocking the role change. Either wait for them to disconnect or use WITH SESSION SHUTDOWN to force disconnect.

-- Check what's blocking switchover
SELECT switchover_status, database_role FROM v$database;

-- Find active sessions
SELECT sid, serial#, username, program, status
FROM v$session
WHERE type = 'USER' AND status = 'ACTIVE'
AND username NOT IN ('SYS','SYSTEM');

Alert log shows: GAP sequence — archived log gap between primary and standby. Usually resolves automatically via FAL (Fetch Archive Log). If not:

-- On primary: check gaps
SELECT * FROM v$archive_gap;

-- Manually register missing logs on standby
ALTER DATABASE REGISTER LOGFILE '/path/to/missing/log';

TuneVault monitors your Data Guard lag, apply status, and transport errors as part of the automated health check. Connect your standby database to track synchronization status without logging into each server manually.