Skip to main content

Oracle Data Guard Switchover to Standby Guide

Oracle Data Guard switchover to standby database overview

Introduction

In Oracle, a switchover is a role transition operation between the primary and standby databases in a Data Guard environment. A switchover lets you swap roles between the primary and standby databases in a planned, controlled manner, without any data loss. This is typically done for maintenance, patching, hardware testing, or periodic load balancing between data centers, and unlike a failover, it's a graceful operation both databases participate in willingly.

Prerequisites

  • Plan for roughly 30 minutes of database downtime during the switchover window.
  • Confirm application and database connectivity are ready at the standby site, since it will become the new primary.
  • Primary and standby databases must be fully in sync before starting. Switching over with a lag risks losing the unapplied redo.

Environment Used in This Guide

These are the primary and standby details used throughout this walkthrough, following on from our earlier standby database setup guide.

Server Primary Standby
Hostname Source Target
IP 192.168.80.51 192.168.80.111
OS OEL 9 OEL 9
SID ORCLDC ORCLDR
Service Name ORCLDC ORCLDR

Step 1: Check Database Status and Sync

Before attempting a switchover, confirm both databases agree on their current roles and that the standby has applied all available redo. An ARC_DIFF of 0 on both sides means there's no unapplied redo, which is the state you want before proceeding.


At Primary:

SQL> select NAME, DB_UNIQUE_NAME, DATABASE_ROLE, OPEN_MODE, SWITCHOVER_STATUS from v$database;

NAME     DB_UNIQUE_NAME         DATABASE_ROLE     OPEN_MODE        SWITCHOVER_STATUS
-------- ---------------------- ----------------- ---------------- --------------------
ORCL     ORCLDC                 PRIMARY           READ WRITE       TO STANDBY

SQL> set lines 200 pages 300
SQL> alter session set nls_date_format= 'DD-MON-YYYY HH24:MI:SS';

Session altered.

SQL> select d.db_unique_name, d.database_role, a.thread#, b.last_seq, a.applied_seq, a.last_app_timestamp, b.last_seq - a.applied_seq ARC_DIFF
FROM
(select thread#, MAX(sequence#) applied_seq, MAX(next_time) last_app_timestamp from gv$archived_log where applied='YES' group by thread#) a,
(select thread#, MAX(sequence#) last_seq from gv$archived_log group by thread#) b,
(select db_unique_name, database_role from v$database) d where a.thread#=b.thread#;

DB_UNIQUE_NAME     DATABASE_ROLE    THREAD#  LAST_SEQ  APPLIED_SEQ  LAST_APP_TIMESTAMP     ARC_DIFF
------------------ ---------------- -------- ---------- ----------- --------------------- ----------
ORCLDC             PRIMARY          1        103        103          08-FEB-2025 20:24:32   0

At Standby:

SQL> select NAME, DB_UNIQUE_NAME, DATABASE_ROLE, OPEN_MODE, SWITCHOVER_STATUS from v$database;

NAME    DB_UNIQUE_NAME    DATABASE_ROLE      OPEN_MODE               SWITCHOVER_STATUS
------- ---------------- ------------------ ------------------------ --------------------
ORCL    ORCLDR            PHYSICAL STANDBY   READ ONLY WITH APPLY    NOT ALLOWED

SQL> set lines 200 pages 300
SQL> alter session set nls_date_format= 'DD-MON-YYYY HH24:MI:SS';

Session altered.

SQL> select d.db_unique_name, d.database_role, a.thread#, b.last_seq, a.applied_seq, b.last_seq - a.applied_seq ARC_DIFF, 
a.last_app_timestamp,
round((sysdate - a.last_app_timestamp) * 24 * 60, 2) Gap_in_Mins, 
round((sysdate - a.last_app_timestamp) * 24 * 60 * 60, 2) Gap_in_Seconds
FROM
(select thread#, MAX(sequence#) applied_seq, MAX(next_time) last_app_timestamp 
 from gv$archived_log where REGISTRAR='RFS' and applied='YES' group by thread#) a,
(select thread#, MAX(sequence#) last_seq from gv$archived_log group by thread#) b,
(select db_unique_name, database_role from v$database) d 
where a.thread# = b.thread#;

DB_UNIQUE_NAME   DATABASE_ROLE      THREAD#  LAST_SEQ  APPLIED_SEQ  ARC_DIFF  LAST_APP_TIMESTAMP     GAP_IN_MINS  GAP_IN_SECONDS
--------------- ------------------ -------- ---------- ----------- ---------- --------------------- ------------ ---------------
ORCLDR           PHYSICAL STANDBY       1        103         103         0     08-FEB-2025 20:24:32       12.85           771

Notice the primary's SWITCHOVER_STATUS shows TO STANDBY, which confirms the primary is in a valid state to switch over. The standby shows NOT ALLOWED, which is expected, the standby can't initiate the switchover itself, that command runs from the primary side.

Step 2: Verify the Switchover

Before actually switching, run a verify-only pass. This checks for problems without making any real changes, giving you a safe way to catch issues in advance.


SQL> alter database switchover to orcldr verify;
 
Database altered.

 

If this completes with no errors, you're clear to proceed to the actual switchover. If you see a warning like the one below, check the database alert log before continuing, since it usually points to a specific unresolved issue (a lagging standby, a missing archive log, or a configuration mismatch).


SQL>  alter database switchover to orcldr verify
  alter database switchover to orcldr verify
  *
ERROR at line 1:
ORA-16475: succeeded with warnings, check alert log for more details

Step 3: Perform the Switchover

With verification clean, run the actual switchover command on the primary. Keep an eye on the alert log during this step, it will show Oracle working through the role transition in real time.


SQL> alter database switchover to orcldr;

Database altered.

Step 4: Start the New Primary and New Standby

After the switchover command completes, both databases are left in a mounted state with their roles swapped. Start the new primary fully open for read/write, and start the new standby in mount mode with managed recovery running.


At new Primary:

SQL> startup
ORACLE instance started.
Total System Global Area 1459616616 bytes
Fixed Size                  9177960 bytes
Variable Size            905969664 bytes
Database Buffers         536870912 bytes
Redo Buffers               7598080 bytes
Database mounted.
Database opened.

SQL> select NAME, DB_UNIQUE_NAME, DATABASE_ROLE, OPEN_MODE, LOG_MODE from v$database;

NAME    DB_UNIQUE_NAME   DATABASE_ROLE   OPEN_MODE       LOG_MODE
------- ---------------- --------------- ---------------- ------------
ORCL    ORCLDR           PRIMARY         READ WRITE       ARCHIVELOG

At new Standby:

SQL> startup mount;
ORACLE instance started.
Total System Global Area 1459616616 bytes
Fixed Size                  9177960 bytes
Variable Size            1157627904 bytes
Database Buffers         285212672 bytes
Redo Buffers               7598080 bytes
Database mounted.

SQL> select NAME, DB_UNIQUE_NAME, DATABASE_ROLE, OPEN_MODE, LOG_MODE from v$database;

NAME    DB_UNIQUE_NAME   DATABASE_ROLE     OPEN_MODE         LOG_MODE
------- ---------------- ----------------- ----------------- ------------
ORCL    ORCLDC           PHYSICAL STANDBY  MOUNTED           ARCHIVELOG

SQL> alter database recover managed standby database disconnect from session;

Database altered.

Notice the unique names have effectively swapped roles: ORCLDR is now PRIMARY and ORCLDC is now PHYSICAL STANDBY, the reverse of how they started. This confirms the switchover succeeded.

Step 5: Confirm Sync on the New Primary

As a final check, switch a couple of logs on the new primary and confirm the new standby is receiving and applying them, the same verification pattern used during initial setup.


SQL> alter system switch logfile;

System altered.

SQL> /

System altered.

Run the same sync-check queries from Step 1 against both databases to confirm ARC_DIFF is back to 0 on the new standby.

Switching Back

A switchback follows the exact same steps, just in reverse. Run the switchover command from what is now the primary (ORCLDR), pointing at ORCLDC instead, and repeat Steps 2 through 5 exactly as above.

Thank you for reading!

I hope this content has been helpful to you. Your feedback and suggestions are always welcome. Feel free to leave a comment or reach out with any queries.

Abhishek Shrivastava

Oracle DBA with hands-on experience managing production Data Guard, RAC, GoldenGate, and APEX environments. I write practical, tested installation and troubleshooting guides based on real deployment work.

📧 Email: oraeasyy@gmail.com
🌐 Website: www.oraeasy.com

Follow Us

Comments