Complete Standby Database Setup from Scratch
Environment Details (Example)
Primary Server : primary_server IP: 192.168.1.10
Standby Server : standby_server IP: 192.168.1.20
DB Name : ORCL
Primary SID : ORCL
Standby SID : ORCLDG
Oracle Home : /u01/app/oracle/product/19c/dbhome_1
Oracle Base : /u01/app/oracle
PHASE 1 — PRIMARY SERVER PREPARATION
Step 1 — Check Primary Database Mode
-- Must be in ARCHIVELOG mode
SQL> SELECT LOG_MODE FROM V$DATABASE;
-- If NOARCHIVELOG, enable it
SQL> SHUTDOWN IMMEDIATE;
SQL> STARTUP MOUNT;
SQL> ALTER DATABASE ARCHIVELOG;
SQL> ALTER DATABASE OPEN;
-- Verify
SQL> SELECT LOG_MODE FROM V$DATABASE;
-- OUTPUT: ARCHIVELOG
Step 2 — Enable Force Logging on Primary
SQL> ALTER DATABASE FORCE LOGGING;
-- Verify
SQL> SELECT FORCE_LOGGING FROM V$DATABASE;
-- OUTPUT: YES
Step 3 — Enable Flashback (Recommended)
SQL> ALTER DATABASE FLASHBACK ON;
-- Verify
SQL> SELECT FLASHBACK_ON FROM V$DATABASE;
Step 4 — Create Standby Redo Logs on Primary
-- Formula: (primary redo log groups + 1) x threads
-- Example: Primary has 3 groups → create 4 SRL groups
-- Check existing redo log size first
SQL> SELECT GROUP#, BYTES/1024/1024 MB FROM V$LOG;
-- Create Standby Redo Logs (same size as online redo logs)
SQL> ALTER DATABASE ADD STANDBY LOGFILE GROUP 4
'/u01/app/oracle/oradata/ORCL/stdby_redo04.log' SIZE 200M;
SQL> ALTER DATABASE ADD STANDBY LOGFILE GROUP 5
'/u01/app/oracle/oradata/ORCL/stdby_redo05.log' SIZE 200M;
SQL> ALTER DATABASE ADD STANDBY LOGFILE GROUP 6
'/u01/app/oracle/oradata/ORCL/stdby_redo06.log' SIZE 200M;
SQL> ALTER DATABASE ADD STANDBY LOGFILE GROUP 7
'/u01/app/oracle/oradata/ORCL/stdby_redo07.log' SIZE 200M;
-- Verify
SQL> SELECT GROUP#, MEMBER FROM V$STANDBY_LOG;
Step 5 — Configure Primary init.ora / spfile Parameters
-- Check current parameter file type
SQL> SHOW PARAMETER spfile;
-- Set Data Guard parameters on PRIMARY
SQL> ALTER SYSTEM SET LOG_ARCHIVE_MODE=TRUE SCOPE=SPFILE;
SQL> ALTER SYSTEM SET LOG_ARCHIVE_DEST_1=
'LOCATION=/u01/app/oracle/archivelog/ORCL/
VALID_FOR=(ALL_LOGFILES,ALL_ROLES)
DB_UNIQUE_NAME=ORCL' SCOPE=BOTH;
SQL> ALTER SYSTEM SET LOG_ARCHIVE_DEST_2=
'SERVICE=ORCLDG LGWR ASYNC
VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE)
DB_UNIQUE_NAME=ORCLDG' SCOPE=BOTH;
SQL> ALTER SYSTEM SET LOG_ARCHIVE_DEST_STATE_1=ENABLE SCOPE=BOTH;
SQL> ALTER SYSTEM SET LOG_ARCHIVE_DEST_STATE_2=ENABLE SCOPE=BOTH;
SQL> ALTER SYSTEM SET LOG_ARCHIVE_FORMAT='%t_%s_%r.arc' SCOPE=SPFILE;
SQL> ALTER SYSTEM SET DB_UNIQUE_NAME='ORCL' SCOPE=SPFILE;
SQL> ALTER SYSTEM SET LOG_ARCHIVE_CONFIG=
'DG_CONFIG=(ORCL,ORCLDG)' SCOPE=BOTH;
SQL> ALTER SYSTEM SET FAL_SERVER='ORCLDG' SCOPE=BOTH;
SQL> ALTER SYSTEM SET FAL_CLIENT='ORCL' SCOPE=BOTH;
SQL> ALTER SYSTEM SET STANDBY_FILE_MANAGEMENT='AUTO' SCOPE=BOTH;
SQL> ALTER SYSTEM SET DB_FILE_NAME_CONVERT=
'/oradata/ORCL/','/oradata/ORCLDG/' SCOPE=SPFILE;
SQL> ALTER SYSTEM SET LOG_FILE_NAME_CONVERT=
'/oradata/ORCL/','/oradata/ORCLDG/' SCOPE=SPFILE;
Step 6 — Configure listener.ora on Primary
# Edit /u01/app/oracle/product/19c/dbhome_1/network/admin/listener.ora
vi $ORACLE_HOME/network/admin/listener.ora
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = primary_server)(PORT = 1521))
)
)
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(GLOBAL_DBNAME = ORCL)
(ORACLE_HOME = /u01/app/oracle/product/19c/dbhome_1)
(SID_NAME = ORCL)
)
(SID_DESC =
(GLOBAL_DBNAME = ORCL_DGMGRL)
(ORACLE_HOME = /u01/app/oracle/product/19c/dbhome_1)
(SID_NAME = ORCL)
)
)
Step 7 — Configure tnsnames.ora on Primary
vi $ORACLE_HOME/network/admin/tnsnames.ora
ORCL =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = primary_server)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = ORCL)
)
)
ORCLDG =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = standby_server)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = ORCLDG)
)
)
# Reload listener
lsnrctl reload
lsnrctl status
Step 8 — Create Password File on Primary
# Check existing password file
ls $ORACLE_HOME/dbs/orapwORCL
# Create if not exists
orapwd file=$ORACLE_HOME/dbs/orapwORCL password=SysPassword123 entries=10
# Copy password file to standby (MUST be identical)
scp $ORACLE_HOME/dbs/orapwORCL \
oracle@standby_server:$ORACLE_HOME/dbs/orapwORCLDG
PHASE 2 — STANDBY SERVER PREPARATION
Step 9 — Create Directory Structure on Standby
# Login to standby server as oracle user
ssh oracle@standby_server
# Create all required directories
mkdir -p /u01/app/oracle/oradata/ORCLDG
mkdir -p /u01/app/oracle/archivelog/ORCLDG
mkdir -p /u01/app/oracle/fast_recovery_area/ORCLDG
mkdir -p /u01/app/oracle/admin/ORCLDG/adump
mkdir -p /u01/app/oracle/admin/ORCLDG/bdump
mkdir -p /u01/app/oracle/admin/ORCLDG/cdump
mkdir -p /u01/app/oracle/admin/ORCLDG/udump
mkdir -p /u01/app/oracle/admin/ORCLDG/pfile
mkdir -p /backup/standby
# Set correct permissions
chown -R oracle:oinstall /u01/app/oracle/oradata/ORCLDG
chown -R oracle:oinstall /u01/app/oracle/archivelog/ORCLDG
chown -R oracle:oinstall /u01/app/oracle/fast_recovery_area/ORCLDG
chown -R oracle:oinstall /u01/app/oracle/admin/ORCLDG
chown -R oracle:oinstall /backup/standby
chmod -R 755 /u01/app/oracle/oradata/ORCLDG
chmod -R 755 /u01/app/oracle/archivelog/ORCLDG
# Verify directories
ls -lR /u01/app/oracle/oradata/ORCLDG
ls -lR /u01/app/oracle/admin/ORCLDG
Step 10 — Create standby init.ora on Standby
vi /u01/app/oracle/admin/ORCLDG/pfile/init_ORCLDG.ora
# ── Database Identity ──────────────────────────────────
*.db_name='ORCL' # Same as primary
*.db_unique_name='ORCLDG' # Different from primary
*.db_domain=''
# ── Instance ───────────────────────────────────────────
*.instance_name='ORCLDG'
# ── Memory ─────────────────────────────────────────────
*.sga_target=2G
*.pga_aggregate_target=512M
*.memory_target=0
# ── Paths ──────────────────────────────────────────────
*.db_create_file_dest='/u01/app/oracle/oradata/ORCLDG'
*.db_recovery_file_dest='/u01/app/oracle/fast_recovery_area/ORCLDG'
*.db_recovery_file_dest_size=50G
*.audit_file_dest='/u01/app/oracle/admin/ORCLDG/adump'
*.core_dump_dest='/u01/app/oracle/admin/ORCLDG/cdump'
*.background_dump_dest='/u01/app/oracle/admin/ORCLDG/bdump'
*.user_dump_dest='/u01/app/oracle/admin/ORCLDG/udump'
# ── File Name Convert (Primary path → Standby path) ───
*.db_file_name_convert=
'/u01/app/oracle/oradata/ORCL/',
'/u01/app/oracle/oradata/ORCLDG/'
*.log_file_name_convert=
'/u01/app/oracle/oradata/ORCL/',
'/u01/app/oracle/oradata/ORCLDG/'
# ── Archivelog ─────────────────────────────────────────
*.log_archive_dest_1=
'LOCATION=/u01/app/oracle/archivelog/ORCLDG/
VALID_FOR=(ALL_LOGFILES,ALL_ROLES)
DB_UNIQUE_NAME=ORCLDG'
*.log_archive_dest_2=
'SERVICE=ORCL LGWR ASYNC
VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE)
DB_UNIQUE_NAME=ORCL'
*.log_archive_dest_state_1=ENABLE
*.log_archive_dest_state_2=ENABLE
*.log_archive_format='%t_%s_%r.arc'
*.log_archive_config='DG_CONFIG=(ORCL,ORCLDG)'
# ── Data Guard ─────────────────────────────────────────
*.fal_server='ORCL'
*.fal_client='ORCLDG'
*.standby_file_management='AUTO'
# ── Redo Transport ─────────────────────────────────────
*.remote_login_passwordfile='EXCLUSIVE'
# ── Misc ───────────────────────────────────────────────
*.compatible='19.0.0'
*.open_cursors=300
*.processes=300
*.undo_tablespace='UNDOTBS1'
*.control_files='/u01/app/oracle/oradata/ORCLDG/control01.ctl',
'/u01/app/oracle/oradata/ORCLDG/control02.ctl'
Step 11 — Configure listener.ora on Standby
vi $ORACLE_HOME/network/admin/listener.ora
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = standby_server)(PORT = 1521))
)
)
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(GLOBAL_DBNAME = ORCLDG)
(ORACLE_HOME = /u01/app/oracle/product/19c/dbhome_1)
(SID_NAME = ORCLDG)
)
(SID_DESC =
(GLOBAL_DBNAME = ORCLDG_DGMGRL)
(ORACLE_HOME = /u01/app/oracle/product/19c/dbhome_1)
(SID_NAME = ORCLDG)
)
)
Step 12 — Configure tnsnames.ora on Standby
vi $ORACLE_HOME/network/admin/tnsnames.ora
ORCL =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = primary_server)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = ORCL)
)
)
ORCLDG =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = standby_server)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = ORCLDG)
)
)
# Start listener on standby
lsnrctl start
lsnrctl status
Step 13 — Set Oracle Environment on Standby
# Edit .bash_profile on standby
vi ~/.bash_profile
export ORACLE_BASE=/u01/app/oracle
export ORACLE_HOME=/u01/app/oracle/product/19c/dbhome_1
export ORACLE_SID=ORCLDG
export PATH=$ORACLE_HOME/bin:$PATH
export LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib
export NLS_DATE_FORMAT='DD-MON-YYYY HH24:MI:SS'
# Apply
source ~/.bash_profile
# Verify
echo $ORACLE_SID
Step 14 — Test Connectivity Between Primary and Standby
# From primary — test connection to standby
tnsping ORCLDG
# From standby — test connection to primary
tnsping ORCL
# Test RMAN connection from standby
rman TARGET sys/password@ORCL
rman TARGET sys/password@ORCLDG
PHASE 3 — BUILD STANDBY USING RMAN DUPLICATE
Step 15 — Start Standby in NOMOUNT
# On standby server
export ORACLE_SID=ORCLDG
sqlplus / as sysdba
SQL> STARTUP NOMOUNT PFILE='/u01/app/oracle/admin/ORCLDG/pfile/init_ORCLDG.ora';
Step 16 — Run RMAN DUPLICATE from Standby Server
# Connect RMAN to both primary (TARGET) and standby (AUXILIARY)
rman TARGET sys/SysPassword123@ORCL \
AUXILIARY sys/SysPassword123@ORCLDG
RMAN> DUPLICATE TARGET DATABASE FOR STANDBY
FROM ACTIVE DATABASE
DORECOVER
SPFILE
PARAMETER_VALUE_CONVERT
'/u01/app/oracle/oradata/ORCL/',
'/u01/app/oracle/oradata/ORCLDG/'
SET db_unique_name='ORCLDG'
SET db_file_name_convert=
'/u01/app/oracle/oradata/ORCL/',
'/u01/app/oracle/oradata/ORCLDG/'
SET log_file_name_convert=
'/u01/app/oracle/oradata/ORCL/',
'/u01/app/oracle/oradata/ORCLDG/'
SET control_files=
'/u01/app/oracle/oradata/ORCLDG/control01.ctl',
'/u01/app/oracle/oradata/ORCLDG/control02.ctl'
SET log_archive_dest_1=
'LOCATION=/u01/app/oracle/archivelog/ORCLDG/'
SET fal_server='ORCL'
SET fal_client='ORCLDG'
SET standby_file_management='AUTO'
NOFILENAMECHECK;
RMAN will now automatically copy all datafiles, controlfile, and apply archivelogs. This may take time depending on DB size.
PHASE 4 — POST DUPLICATE STEPS
Step 17 — Create spfile from pfile on Standby
SQL> CREATE SPFILE FROM PFILE=
'/u01/app/oracle/admin/ORCLDG/pfile/init_ORCLDG.ora';
-- Restart using spfile
SQL> SHUTDOWN IMMEDIATE;
SQL> STARTUP MOUNT;
Step 18 — Start MRP Apply Process
-- Start Managed Recovery Process
SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE
DISCONNECT FROM SESSION;
-- OR with real-time apply (preferred)
SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE
USING CURRENT LOGFILE
DISCONNECT FROM SESSION;
Step 19 — Verify Standby is Working
-- Check database role
SQL> SELECT DB_UNIQUE_NAME, DATABASE_ROLE, OPEN_MODE,
PROTECTION_MODE FROM V$DATABASE;
-- Check MRP process
SQL> SELECT PROCESS, STATUS, SEQUENCE#,
BLOCKS FROM V$MANAGED_STANDBY;
-- Check archive log apply status
SQL> SELECT SEQUENCE#, APPLIED, FIRST_TIME,
NEXT_TIME FROM V$ARCHIVED_LOG
ORDER BY SEQUENCE# DESC;
-- Check gap between primary and standby
SQL> SELECT * FROM V$ARCHIVE_GAP;
-- Compare sequences
-- On Primary:
SQL> SELECT MAX(SEQUENCE#) FROM V$ARCHIVED_LOG;
-- On Standby:
SQL> SELECT MAX(SEQUENCE#) FROM V$ARCHIVED_LOG
WHERE APPLIED = 'YES';
Complete Checklist
PRIMARY SIDE
─────────────────────────────────────────────────
[ ] Database in ARCHIVELOG mode
[ ] FORCE LOGGING enabled
[ ] Standby Redo Logs created
[ ] LOG_ARCHIVE_DEST_2 pointing to standby
[ ] LOG_ARCHIVE_CONFIG set
[ ] FAL_SERVER / FAL_CLIENT set
[ ] listener.ora updated with static entry
[ ] tnsnames.ora has both ORCL and ORCLDG entries
[ ] Password file created and copied to standby
STANDBY SIDE
─────────────────────────────────────────────────
[ ] All directories created with correct permissions
[ ] init_ORCLDG.ora created with standby parameters
[ ] db_file_name_convert set correctly
[ ] log_file_name_convert set correctly
[ ] listener.ora configured with static SID entry
[ ] tnsnames.ora has both entries
[ ] ORACLE_SID set to ORCLDG in .bash_profile
[ ] tnsping working both ways
[ ] STARTUP NOMOUNT successful
[ ] DUPLICATE completed without errors
[ ] spfile created from pfile
[ ] MRP process started
[ ] Sequence# in sync with primary
[ ] No gaps in V$ARCHIVE_GAP
Key Points to Remember
| Item |
Value |
db_name |
Same on primary and standby |
db_unique_name |
Different (ORCL vs ORCLDG) |
| Password file |
Must be identical on both |
| Standby Redo Logs |
Must exist on both servers |
NOFILENAMECHECK |
Use when directory paths are different |
| MRP |
Must be running for real-time sync |
After switchover
|
Always take fresh Level 0 backup
|
___________________________________***______________________________________
Minimal init.ora for Standby Database
Absolute Minimum Parameters Required
# /u01/app/oracle/admin/ORCLDG/pfile/init_ORCLDG.ora
# ── Must Have ──────────────────────────────────────────
# Same as primary db_name
db_name='ORCL'
# Unique name for standby
db_unique_name='ORCLDG'
# Controlfile location on standby
control_files='/u01/app/oracle/oradata/ORCLDG/control01.ctl',
'/u01/app/oracle/oradata/ORCLDG/control02.ctl'
# Convert primary paths to standby paths
db_file_name_convert='/u01/app/oracle/oradata/ORCL/',
'/u01/app/oracle/oradata/ORCLDG/'
log_file_name_convert='/u01/app/oracle/oradata/ORCL/',
'/u01/app/oracle/oradata/ORCLDG/'
# Required for redo transport authentication
remote_login_passwordfile='EXCLUSIVE'
# Audit directory must exist
audit_file_dest='/u01/app/oracle/admin/ORCLDG/adump'
# Oracle version compatibility
compatible='19.0.0'