Tuesday, September 9, 2025

Recover a table from RMAN backup



  • Introduction: We can recover specific tables in Oracle using RMAN’s RECOVER TABLE command with a timestamp or SCN, which restores tables via an auxiliary instance without impacting production. The recovered table is then exported with Data Pump and imported back into the target database, ensuring precise point-in-time recovery without affecting the rest of the environment. In this article, we will do the Table recovery with RMAN backup.

  • Prerequisites:
    • A valid RMAN backup prior to table drop.
    • Disk space requirement is depending upon the Table & its related Tablespace size. Apart from this additional 5-10 GB for auxiliary instance.
  • Environment:
  • Server test.oraeasy.com
    Database Name testdb
    Database Version 19.27

  • Now let's proceed to recover the table via RMAN step by step:

1. First create a table.

SQL> DEF
DEFINE _DATE           = "23-AUG-25" (CHAR)
DEFINE _CONNECT_IDENTIFIER = "testdb" (CHAR)
DEFINE _USER           = "TEST" (CHAR)
DEFINE _PRIVILEGE      = "" (CHAR)
DEFINE _SQLPLUS_RELEASE = "1927000000" (CHAR)
DEFINE _EDITOR         = "vi" (CHAR)
DEFINE _O_VERSION      = "Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.27.0.0.0" (CHAR)
DEFINE _O_RELEASE      = "1927000000" (CHAR)
SQL>
SQL> SHOW USER
USER is "TEST"
SQL>

SQL> CREATE TABLE company (
       emp_id   INT,
       name     VARCHAR(255),
       company  VARCHAR(255)
    );

Table created.

SQL> INSERT INTO company VALUES (101, 'Yash', 'WIPRO');

1 row created.

SQL> INSERT INTO company VALUES (102, 'Vijay', 'AIRTEL');

1 row created.

SQL> INSERT INTO company VALUES (103, 'Riya', 'TCS');

1 row created.

SQL> COMMIT;

Commit complete.

SQL> SELECT COUNT(*) FROM company;

  COUNT(*)
----------
         3
2. Now take full database backup using RMAN.
 
[oracle@test ~]$ RMAN TARGET /

Recovery Manager: Release 19.0.0.0.0 - Production on Sat Aug 23 10:10:58 2025
Version 19.27.0.0.0

Copyright (c) 1982, 2019, Oracle and/or its affiliates.  All rights reserved.

connected to target database: testdb (DBID=877553793)

RMAN>
RMAN> RUN
{
    ALLOCATE CHANNEL ch1 DEVICE TYPE DISK;
    BACKUP AS COMPRESSED BACKUPSET DATABASE FORMAT '/u01/rman/Fullback_%T_%U';
    BACKUP AS COMPRESSED BACKUPSET ARCHIVELOG ALL FORMAT '/u01/rman/Archive_%T_%U';
    RELEASE CHANNEL ch1;
}  
using target database control file instead of recovery catalog
allocated channel: ch1
channel ch1: SID=58 device type=DISK

Starting backup at 23-AUG-25
channel ch1: starting compressed full datafile backup set
channel ch1: specifying datafile(s) in backup set
input datafile file number=00001 name=/u01/app/oracle/oradata/testdb/system01.dbf
input datafile file number=00002 name=/u01/app/oracle/oradata/testdb/sysaux01.dbf
input datafile file number=00004 name=/u01/app/oracle/oradata/testdb/undotbs01.dbf
input datafile file number=00003 name=/u01/app/oracle/oradata/testdb/users01.dbf
channel ch1: starting piece 1 at 23-AUG-25
channel ch1: finished piece 1 at 23-AUG-25
piece handle=/u01/rman/Fullback_20250823_0341r31u_3_1_1 tag=TAG20250823T101317 comment=NONE
channel ch1: backup set complete, elapsed time: 00:06:34
Finished backup at 23-AUG-25

Starting backup at 23-AUG-25
current log archived
channel ch1: starting compressed archived log backup set
channel ch1: specifying archived log(s) in backup set
input archived log thread=1 sequence=12 RECID=2 STAMP=1209298467
input archived log thread=1 sequence=13 RECID=3 STAMP=1209298492
input archived log thread=1 sequence=14 RECID=4 STAMP=1209298520
input archived log thread=1 sequence=15 RECID=5 STAMP=1209298532
input archived log thread=1 sequence=16 RECID=6 STAMP=1209298534
input archived log thread=1 sequence=17 RECID=7 STAMP=1209302329
input archived log thread=1 sequence=18 RECID=8 STAMP=1209303449
input archived log thread=1 sequence=19 RECID=9 STAMP=1209304855
input archived log thread=1 sequence=20 RECID=10 STAMP=1209305991
input archived log thread=1 sequence=21 RECID=11 STAMP=1209307464
input archived log thread=1 sequence=22 RECID=12 STAMP=1209310175
input archived log thread=1 sequence=23 RECID=13 STAMP=1209314873
input archived log thread=1 sequence=24 RECID=14 STAMP=1209322002
input archived log thread=1 sequence=25 RECID=15 STAMP=1209896476
channel ch1: starting piece 1 at 23-AUG-25
channel ch1: finished piece 1 at 23-AUG-25
piece handle=/u01/rman/Archive_20250823_0441r3hb_4_1_1 tag=TAG20250823T102128 comment=NONE
channel ch1: backup set complete, elapsed time: 00:08:32
Finished backup at 23-AUG-25

Starting Control File and SPFILE Autobackup at 23-AUG-25
piece handle=/u01/app/oracle/fast_recovery_area/testdb/autobackup/2025_08_23/o1_mf_s_1209897017_nbllql1r_.bkp comment=NONE
Finished Control File and SPFILE Autobackup at 23-AUG-25

released channel: ch1

RMAN>
RMAN> exit
3. Now check the current timestamp.
 
SQL> SELECT TO_CHAR (SYSDATE, 'MM-DD-YYYY HH24:MI:SS') "Current_Timestamp" FROM DUAL;

Current_Timestamp
-------------------
08-23-2025 10:32:05
4. Now drop the table.
  
SQL> DROP TABLE test.company;

Table dropped.

SQL> SELECT TO_CHAR (SYSDATE, 'MM-DD-YYYY HH24:MI:SS') "Current_Timestamp" FROM DUAL;

Current_Timestamp
-------------------
08-23-2025 10:37:07
5. Create directory for placing the files for auxiliary instance & storing the dump file.

[oracle@test ~]$ mkdir -p /u01/data
[oracle@test ~]$ mkdir -p /u01/dpump

6. Now run the Recover Table script.
Syntax:
RECOVER TABLE test.company -- recover table COMPANY from schema TEST
UNTIL TIME "TO_DATE('08/23/2025 10:32:00', 'MM/DD/YYYY HH24:MI:SS')" -- recover it as of this timestamp
AUXILIARY DESTINATION '/u01/data' -- use this location for temporary auxiliary instance files
DATAPUMP DESTINATION '/u01/dpump' -- store the Data Pump export here
DUMP FILE 'company_exp.dmp'; -- name of the Data Pump dump file to generate

RMAN> RECOVER TABLE test.company
  UNTIL TIME "TO_DATE('08/23/2025 10:32:00', 'MM/DD/YYYY HH24:MI:SS')"
  AUXILIARY DESTINATION '/u01/data'
  DATAPUMP DESTINATION '/u01/dpump'
  DUMP FILE 'company_exp.dmp';

Starting recover at 23-AUG-25
using target database control file instead of recovery catalog
current log archived
allocated channel: ORA_DISK_1
channel ORA_DISK_1: SID=497 device type=DISK
RMAN-05026: warning: presuming following set of tablespaces applies to specified point-in-time

List of tablespaces expected to have UNDO segments
Tablespace SYSTEM
Tablespace UNDOTBS1

Creating automatic instance, with SID='hput'

initialization parameters used for automatic instance:
db_name=testdb
db_unique_name=hput_pitr_testdb
compatible=19.0.0
db_block_size=8192
db_files=200
diagnostic_dest=/u01/app/oracle
_pdb_name_case_sensitive=false
_system_trig_enabled=FALSE
sga_target=1200M
processes=200
db_create_file_dest=/u01/data
log_archive_dest_1='location=/u01/data'
#No auxiliary parameter file used


starting up automatic instance testdb

Oracle instance started

Total System Global Area    1258288760 bytes

Fixed Size                     8939128 bytes
Variable Size                318767104 bytes
Database Buffers             922746880 bytes
Redo Buffers                   7835648 bytes
Automatic instance created

contents of Memory Script:
{
# set requested point in time
set until  time "TO_DATE('08/23/2025 10:32:00','MM/DD/YYYY HH24:MI:SS')";
# restore the controlfile
restore clone controlfile;

# mount the controlfile
sql clone 'alter database mount clone database';

# archive current online log
sql 'alter system archive log current';
}
executing Memory Script

executing command: SET until clause

Starting restore at 23-AUG-25
allocated channel: ORA_AUX_DISK_1
channel ORA_AUX_DISK_1: SID=19 device type=DISK

channel ORA_AUX_DISK_1: starting datafile backup set restore
channel ORA_AUX_DISK_1: restoring control file
channel ORA_AUX_DISK_1: reading from backup piece /u01/app/oracle/fast_recovery_area/testdb/autobackup/2025_08_23/o1_mf_s_1209897017_nbllql1r_.bkp
channel ORA_AUX_DISK_1: piece handle=/u01/app/oracle/fast_recovery_area/testdb/autobackup/2025_08_23/o1_mf_s_1209897017_nbllql1r_.bkp tag=TAG20250823T103011
channel ORA_AUX_DISK_1: restored backup piece 1
channel ORA_AUX_DISK_1: restore complete, elapsed time: 00:00:04
output file name=/u01/data/testdb/controlfile/o1_mf_nblms0lh_.ctl
Finished restore at 23-AUG-25

sql statement: alter database mount clone database

sql statement: alter system archive log current

contents of Memory Script:
{
# set requested point in time
set until  time "TO_DATE('08/23/2025 10:32:00','MM/DD/YYYY HH24:MI:SS')";
# set destinations for recovery set and auxiliary set datafiles
set newname for clone datafile  1 to new;
set newname for clone datafile  4 to new;
set newname for clone datafile  3 to new;
set newname for clone tempfile  1 to new;
# switch all tempfiles
switch clone tempfile all;
# restore the tablespaces in the recovery set and the auxiliary set
restore clone datafile  1, 4, 3;

switch clone datafile all;
}
executing Memory Script

executing command: SET until clause

executing command: SET NEWNAME

executing command: SET NEWNAME

executing command: SET NEWNAME

executing command: SET NEWNAME

renamed tempfile 1 to /u01/data/testdb/datafile/o1_mf_temp_%u_.tmp in control file

Starting restore at 23-AUG-25
using channel ORA_AUX_DISK_1

channel ORA_AUX_DISK_1: starting datafile backup set restore
channel ORA_AUX_DISK_1: specifying datafile(s) to restore from backup set
channel ORA_AUX_DISK_1: restoring datafile 00001 to /u01/data/testdb/datafile/o1_mf_system_%u_.dbf
channel ORA_AUX_DISK_1: restoring datafile 00004 to /u01/data/testdb/datafile/o1_mf_undotbs1_%u_.dbf
channel ORA_AUX_DISK_1: restoring datafile 00003 to /u01/data/testdb/datafile/o1_mf_sysaux_%u_.dbf
channel ORA_AUX_DISK_1: reading from backup piece /u01/rman/Fullback_20250823_0341r31u_3_1_1
channel ORA_AUX_DISK_1: piece handle=/u01/rman/Fullback_20250823_0341r31u_3_1_1 tag=TAG20250823T101317
channel ORA_AUX_DISK_1: restored backup piece 1
channel ORA_AUX_DISK_1: restore complete, elapsed time: 00:04:09
Finished restore at 23-AUG-25

datafile 1 switched to datafile copy
input datafile copy RECID=4 STAMP=1209898456 file name=/u01/data/testdb/datafile/o1_mf_system_nblmvrso_.dbf
datafile 4 switched to datafile copy
input datafile copy RECID=5 STAMP=1209898460 file name=/u01/data/testdb/datafile/o1_mf_undotbs1_nblmvt0b_.dbf
datafile 3 switched to datafile copy
input datafile copy RECID=6 STAMP=1209898463 file name=/u01/data/testdb/datafile/o1_mf_sysaux_nblmvspf_.dbf

contents of Memory Script:
{
# set requested point in time
set until  time "TO_DATE('08/23/2025 10:32:00','MM/DD/YYYY HH24:MI:SS')";
# online the datafiles restored or switched
sql clone "alter database datafile  1 online";
sql clone "alter database datafile  4 online";
sql clone "alter database datafile  3 online";
# recover and open database read only
recover clone database tablespace  "SYSTEM", "UNDOTBS1", "SYSAUX";
sql clone 'alter database open read only';
}
executing Memory Script

executing command: SET until clause

sql statement: alter database datafile  1 online

sql statement: alter database datafile  4 online

sql statement: alter database datafile  3 online

Starting recover at 23-AUG-25
using channel ORA_AUX_DISK_1

Executing: alter database datafile 2, 5, 7, 8 offline
starting media recovery

archived log for thread 1 with sequence 25 is already on disk as file /u01/app/oracle/fast_recovery_area/testdb/archivelog/2025_08_23/o1_mf_1_25_nbll44m7_.arc
archived log for thread 1 with sequence 26 is already on disk as file /u01/app/oracle/fast_recovery_area/testdb/archivelog/2025_08_23/o1_mf_1_26_nblm8msp_.arc
archived log file name=/u01/app/oracle/fast_recovery_area/testdb/archivelog/2025_08_23/o1_mf_1_25_nbll44m7_.arc thread=1 sequence=25
archived log file name=/u01/app/oracle/fast_recovery_area/testdb/archivelog/2025_08_23/o1_mf_1_26_nblm8msp_.arc thread=1 sequence=26
media recovery complete, elapsed time: 00:02:24
Finished recover at 23-AUG-25

sql statement: alter database open read only

contents of Memory Script:
{
   sql clone "create spfile from memory";
   shutdown clone immediate;
   startup clone nomount;
   sql clone "alter system set  control_files =
  ''/u01/data/testdb/controlfile/o1_mf_nblms0lh_.ctl'' comment=
 ''RMAN set'' scope=spfile";
   shutdown clone immediate;
   startup clone nomount;
# mount database
sql clone 'alter database mount clone database';
}
executing Memory Script

sql statement: create spfile from memory

database closed
database dismounted
Oracle instance shut down

connected to auxiliary database (not started)
Oracle instance started

Total System Global Area    1258288760 bytes

Fixed Size                     8939128 bytes
Variable Size                318767104 bytes
Database Buffers             922746880 bytes
Redo Buffers                   7835648 bytes

sql statement: alter system set  control_files =   ''/u01/data/testdb/controlfile/o1_mf_nblms0lh_.ctl'' comment= ''RMAN set'' scope=spfile

Oracle instance shut down

connected to auxiliary database (not started)
Oracle instance started

Total System Global Area    1258288760 bytes

Fixed Size                     8939128 bytes
Variable Size                318767104 bytes
Database Buffers             922746880 bytes
Redo Buffers                   7835648 bytes

sql statement: alter database mount clone database

contents of Memory Script:
{
# set requested point in time
set until  time "TO_DATE('08/23/2025 10:32:00','MM/DD/YYYY HH24:MI:SS')";
# set destinations for recovery set and auxiliary set datafiles
set newname for datafile  7 to new;
# restore the tablespaces in the recovery set and the auxiliary set
restore clone datafile  7;

switch clone datafile all;
}
executing Memory Script

executing command: SET until clause

executing command: SET NEWNAME

Starting restore at 23-AUG-25
allocated channel: ORA_AUX_DISK_1
channel ORA_AUX_DISK_1: SID=20 device type=DISK

channel ORA_AUX_DISK_1: starting datafile backup set restore
channel ORA_AUX_DISK_1: specifying datafile(s) to restore from backup set
channel ORA_AUX_DISK_1: restoring datafile 00007 to /u01/data/HPUT_PITR_testdb/datafile/o1_mf_users_%u_.dbf
channel ORA_AUX_DISK_1: reading from backup piece /u01/rman/Fullback_20250823_0341r31u_3_1_1
channel ORA_AUX_DISK_1: piece handle=/u01/rman/Fullback_20250823_0341r31u_3_1_1 tag=TAG20250823T101317
channel ORA_AUX_DISK_1: restored backup piece 1
channel ORA_AUX_DISK_1: restore complete, elapsed time: 00:00:03
Finished restore at 23-AUG-25

datafile 7 switched to datafile copy
input datafile copy RECID=8 STAMP=1209898997 file name=/u01/data/HPUT_PITR_testdb/datafile/o1_mf_users_nblnns3s_.dbf

contents of Memory Script:
{
# set requested point in time
set until  time "TO_DATE('08/23/2025 10:32:00','MM/DD/YYYY HH24:MI:SS')";
# online the datafiles restored or switched
sql clone "alter database datafile  7 online";
# recover and open resetlogs
recover clone database tablespace  "USERS", "SYSTEM", "UNDOTBS1", "SYSAUX" delete archivelog;
alter clone database open resetlogs;
}
executing Memory Script

executing command: SET until clause

sql statement: alter database datafile  7 online

Starting recover at 23-AUG-25
using channel ORA_AUX_DISK_1

Executing: alter database datafile 2, 5, 8 offline
starting media recovery

archived log for thread 1 with sequence 25 is already on disk as file /u01/app/oracle/fast_recovery_area/testdb/archivelog/2025_08_23/o1_mf_1_25_nbll44m7_.arc
archived log for thread 1 with sequence 26 is already on disk as file /u01/app/oracle/fast_recovery_area/testdb/archivelog/2025_08_23/o1_mf_1_26_nblm8msp_.arc
archived log file name=/u01/app/oracle/fast_recovery_area/testdb/archivelog/2025_08_23/o1_mf_1_25_nbll44m7_.arc thread=1 sequence=25
archived log file name=/u01/app/oracle/fast_recovery_area/testdb/archivelog/2025_08_23/o1_mf_1_26_nblm8msp_.arc thread=1 sequence=26
media recovery complete, elapsed time: 00:00:07
Finished recover at 23-AUG-25

database opened

contents of Memory Script:
{
# create directory for datapump import
sql "create or replace directory TSPITR_DIROBJ_DPDIR as ''
/u01/dpump''";
# create directory for datapump export
sql clone "create or replace directory TSPITR_DIROBJ_DPDIR as ''
/u01/dpump''";
}
executing Memory Script

sql statement: create or replace directory TSPITR_DIROBJ_DPDIR as ''/u01/dpump''

sql statement: create or replace directory TSPITR_DIROBJ_DPDIR as ''/u01/dpump''

Performing export of tables...
   EXPDP> Starting "SYS"."TSPITR_EXP_hput_joFn":
   EXPDP> Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
   EXPDP> Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
   EXPDP> Processing object type TABLE_EXPORT/TABLE/STATISTICS/MARKER
   EXPDP> Processing object type TABLE_EXPORT/TABLE/TABLE
   EXPDP> . . exported "TEST"."COMPANY"                            5.976 KB       3 rows
   EXPDP> Master table "SYS"."TSPITR_EXP_hput_joFn" successfully loaded/unloaded
   EXPDP> ******************************************************************************
   EXPDP> Dump file set for SYS.TSPITR_EXP_hput_joFn is:
   EXPDP>   /u01/dpump/company_exp.dmp
   EXPDP> Job "SYS"."TSPITR_EXP_hput_joFn" successfully completed at Sat Aug 23 11:24:32 2025 elapsed 0 00:13:02
Export completed


contents of Memory Script:
{
# shutdown clone before import
shutdown clone abort
}
executing Memory Script

Oracle instance shut down

Performing import of tables...
   IMPDP> Master table "SYS"."TSPITR_IMP_hput_Fjcx" successfully loaded/unloaded
   IMPDP> Starting "SYS"."TSPITR_IMP_hput_Fjcx":
   IMPDP> Processing object type TABLE_EXPORT/TABLE/TABLE
   IMPDP> Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
   IMPDP> . . imported "TEST"."COMPANY"                            5.976 KB       3 rows
   IMPDP> Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
   IMPDP> Processing object type TABLE_EXPORT/TABLE/STATISTICS/MARKER
   IMPDP> Job "SYS"."TSPITR_IMP_hput_Fjcx" successfully completed at Sat Aug 23 11:39:43 2025 elapsed 0 00:03:39
Import completed

Removing automatic instance
Automatic instance removed
auxiliary instance file /u01/data/testdb/datafile/o1_mf_temp_nblnc15n_.tmp deleted
auxiliary instance file /u01/data/HPUT_PITR_testdb/onlinelog/o1_mf_7_nblnorlc_.log deleted
auxiliary instance file /u01/data/HPUT_PITR_testdb/onlinelog/o1_mf_6_nblnor5v_.log deleted
auxiliary instance file /u01/data/HPUT_PITR_testdb/onlinelog/o1_mf_5_nblnor4v_.log deleted
auxiliary instance file /u01/data/HPUT_PITR_testdb/onlinelog/o1_mf_4_nblnor40_.log deleted
auxiliary instance file /u01/data/HPUT_PITR_testdb/datafile/o1_mf_users_nblnns3s_.dbf deleted
auxiliary instance file /u01/data/testdb/datafile/o1_mf_sysaux_nblmvspf_.dbf deleted
auxiliary instance file /u01/data/testdb/datafile/o1_mf_undotbs1_nblmvt0b_.dbf deleted
auxiliary instance file /u01/data/testdb/datafile/o1_mf_system_nblmvrso_.dbf deleted
auxiliary instance file /u01/data/testdb/controlfile/o1_mf_nblms0lh_.ctl deleted
auxiliary instance file company_exp.dmp deleted
Finished recover at 23-AUG-25

RMAN> exit
7. Now check the table.

SQL> DEF
DEFINE _DATE           = "23-AUG-25" (CHAR)
DEFINE _CONNECT_IDENTIFIER = "testdb" (CHAR)
DEFINE _USER           = "SYS" (CHAR)
DEFINE _PRIVILEGE      = "AS SYSDBA" (CHAR)
DEFINE _SQLPLUS_RELEASE = "1927000000" (CHAR)
DEFINE _EDITOR         = "vi" (CHAR)
DEFINE _O_VERSION      = "Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.27.0.0.0" (CHAR)
DEFINE _O_RELEASE      = "1927000000" (CHAR)
SQL>

SQL> SELECT COUNT(*) FROM test.company;

  COUNT(*)
----------
         3

If you have CDB/PDB environment then use below syntax.

RECOVER TABLE test.company OF PLUGGABLE DATABASE testpdb
  UNTIL TIME "TO_DATE('08/23/2025 19:55:00', 'MM/DD/YYYY HH24:MI:SS')"
  AUXILIARY DESTINATION '/u01/data'
  DATAPUMP DESTINATION '/u01/dpump'
  DUMP FILE 'company_exp.dmp';

Also if you don't want to import the table in the same database then you can append NOTABLEIMPORT clause in Recover table script like below.

RECOVER TABLE 'TEST'.'COMPANY'
  UNTIL TIME "TO_DATE('08/23/2025 19:55:00','MM/DD/YYYY HH24:MI:SS')"
  AUXILIARY DESTINATION '/u01/data'
  DATAPUMP DESTINATION '/u01/dpump'
  DUMP FILE 'company_exp.dmp'
  NOTABLEIMPORT;


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

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

Tuesday, September 2, 2025

Oracle Database Auditing || FGA



  • Introduction : Oracle Database Auditing is a crucial tool that helps database administrators monitor and record activities occurring within the database environment. By tracking actions such as data modifications, user access, and system changes, auditing provides a detailed record of who did what and when.

  • Types of Auditing in Oracle:
    1. Mandatory Auditing : Certain critical actions or users (like SYSDBA) are audited by default without configuration, ensuring that highly sensitive operations are always tracked. Mandatory Auditing refers to the automatic auditing of specific database actions related to highly privileged users and system-level operations. These include:
      1. Logons by privileged users such as those connecting with the SYSDBA, SYSOPER, or similar administrative roles.
      2. Startup and shutdown operations of the Oracle instance.
      3. DDL statements and DML operations affecting the data dictionary and audit infrastructure.
      4. Direct interactions with audit-related system tables, such as the unified audit trail tables.
    2. Standard Auditing : This traditional auditing method lets you track specific SQL statements and privileges. You can audit actions like SELECT, INSERT, UPDATE, DELETE, DDL commands, and user logins by enabling audit policies using the AUDIT SQL statement.
    3. Fine-Grained Auditing (FGA): FGA provides detailed auditing by allowing you to define specific conditions on which to audit access. For example, you can audit access to particular columns or rows based on user-defined predicates, making it useful for monitoring sensitive data access.
    4. Unified Auditing : Introduced in Oracle 12c, Unified Auditing consolidates all audit records from different sources into a single, centralized audit trail. It simplifies audit management and improves performance by unifying standard, fine-grained, and other audit records.
    Below Table will give the comparison view for different types of auditing.
    Feature Mandatory Auditing Standard Auditing Fine-Grained Auditing (FGA) Unified Auditing
    Purpose Audit critical system activities and SYSDBA/SYSOPER actions Audit general actions (DML, DDL, logins) Audit access to specific rows/columns based on conditions Consolidates all audit types into one unified audit trail
    Configuration Auto-enabled AUDIT / NOAUDIT DBMS_FGA package CREATE AUDIT POLICY + AUDIT statements
    Granularity System-level Statement-level Row & column with conditions All levels unified
    Where Records Are Stored UNIFIED_AUDIT_TRAIL or OS DBA_AUDIT_TRAIL or OS files DBA_FGA_AUDIT_TRAIL UNIFIED_AUDIT_TRAIL view (secure internal table)
    Available In Both Editions Standard & Enterprise Enterprise Only Enterprise Only
    Disablable No Yes Yes Yes (via policy management)

  • AUDIT_TRAIL Parameter :
  • The AUDIT_TRAIL parameter controls whether and where audit records are stored. It's essential for enabling auditing. Below table will give the view of this parameter value.
    Option Description
    NONE Disables auditing. No audit records are generated.
    OS Audit records are written to operating system files.
    DB Audit records are written to the database table AUD$ in the SYS schema.
    DB,EXTENDED Same as DB, but includes SQL statements and bind variables.
    XML Audit records are written to XML files in the location defined by AUDIT_FILE_DEST.
    XML,EXTENDED Same as XML, but includes SQL text and bind values.

    In the previous article we have configured the Standard Auditing.
    Please visit Standard Auditing. So, in this article we will configure the Fine-Grained Auditing (FGA).

  • Environment:
  • Hostname orcl.oraeasy.com
    Database Name orcldb
    Database Version 19.27
    Database Edition Enterprise Edition

  • Prerequisites:
    • 30 min downtime.
    • Sufficient space at tablespace & OS level for storing aduit records.

  • Now proceed for enabling FGA auditing step by step:

1. First we need to set the AUDIT_TRAIL parameter, here we will set this DB,EXTENDED.

==>First Create a pfile:

SQL> SQL> SHOW PDBS CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 ORCLPDB READ WRITE NO SQL> SQL> DEF DEFINE _DATE = "14-AUG-25" (CHAR) DEFINE _CONNECT_IDENTIFIER = "orcldc" (CHAR) DEFINE _USER = "SYS" (CHAR) DEFINE _PRIVILEGE = "AS SYSDBA" (CHAR) DEFINE _SQLPLUS_RELEASE = "1927000000" (CHAR) DEFINE _EDITOR = "vi" (CHAR) DEFINE _O_VERSION = "Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production Version 19.27.0.0.0" (CHAR) DEFINE _O_RELEASE = "1927000000" (CHAR) SQL> SQL> CREATE PFILE='/home/oracle/pfileorcl.ora' FROM SPFILE; File created.

==> Now set the AUDIT_TRAIL parameter. It requires Database bounce.

SQL> SHOW PARAMETER audit NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ audit_file_dest string /u01/app/oracle/admin/orcl/adu mp audit_sys_operations boolean TRUE audit_syslog_level string audit_trail string DB unified_audit_common_systemlog string unified_audit_sga_queue_size integer 1048576 unified_audit_systemlog string SQL> SQL> ALTER SYSTEM SET audit_trail=DB, EXTENDED SCOPE=SPFILE; System altered. SQL> SQL> SHUTDOWN IMMEDIATE; Database closed. Database dismounted. ORACLE instance shut down. SQL> SQL> STARTUP ORACLE instance started. Total System Global Area 524284552 bytes Fixed Size 9179784 bytes Variable Size 432013312 bytes Database Buffers 75497472 bytes Redo Buffers 7593984 bytes Database mounted. Database opened. SQL> SQL> SHOW PARAMETER audit NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ audit_file_dest string /u01/app/oracle/admin/orcl/adu mp audit_sys_operations boolean TRUE audit_syslog_level string audit_trail string DB, EXTENDED unified_audit_common_systemlog string unified_audit_sga_queue_size integer 1048576 unified_audit_systemlog string SQL> SQL> SHOW PDBS CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 ORCLPDB READ WRITE NO SQL> SQL> ALTER SESSION SET CONTAINER=ORCLPDB; Session altered. SQL> SQL> SHOW PARAMETER audit NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ audit_file_dest string /u01/app/oracle/admin/orcl/adu mp audit_sys_operations boolean TRUE audit_syslog_level string audit_trail string DB, EXTENDED unified_audit_common_systemlog string unified_audit_sga_queue_size integer 1048576 unified_audit_systemlog string SQL>
2. Now we need to assign a tablespace for storing the audit data by using DBMS_AUDIT_MGMT package.


SQL> SET LINESIZE 333 PAGESIZE 333
SQL> COLUMN SEGMENT_NAME FORMAT A20
SQL> SELECT segment_name, tablespace_name, blocks, bytes/1024/1024 "Size Mb"
     FROM dba_segments
     WHERE segment_name IN ('FGA_LOG$');

SEGMENT_NAME         TABLESPACE_NAME                    BLOCKS    Size Mb
-------------------- ------------------------------ ---------- ----------
FGA_LOG$                SYSTEM                                  8      .0625

SQL> COLUMN FILE_NAME FORMAT A80
SQL> SELECT file_name, tablespace_name, bytes/1024/1024, status, autoextensible
     FROM dba_data_files
     WHERE tablespace_name IN ('SYSTEM'

FILE_NAME                                             TABLESPACE_NAME                BYTES/1024/1024 STATUS    AUT
----------------------------------------------------- ------------------------------ --------------- --------- ---
/u01/app/oracle/oradata/ORCL/orclpdb/system01.dbf     SYSTEM                                     680 AVAILABLE YES

SQL> CREATE TABLESPACE audit_data 
     DATAFILE '/u01/app/oracle/oradata/ORCL/orclpdb/audit_data01.dbf' 
     SIZE 1G AUTOEXTEND ON;

Tablespace created.


SQL> SELECT file_name, tablespace_name, bytes/1024/1024, status, autoextensible
     FROM dba_data_files
     WHERE tablespace_name IN ('AUDIT_DATA');

FILE_NAME                                               TABLESPACE_NAME                BYTES/1024/1024 STATUS    AUT
------------------------------------------------------  ---------------------------- --------------- --------- ---
/u01/app/oracle/oradata/ORCL/orclpdb/audit_data01.dbf   AUDIT_DATA                                1024 AVAILABLE YES

SQL>
SQL> BEGIN
         dbms_audit_mgmt.set_audit_trail_location(
             audit_trail_type => dbms_audit_mgmt.audit_trail_fga_std,
             audit_trail_location_value => 'AUDIT_DATA');
     END;
     / 
     
PL/SQL procedure successfully completed.

SQL> SELECT segment_name, tablespace_name, blocks, bytes/1024/1024 "Size Mb"
     FROM dba_segments
     WHERE segment_name IN ('FGA_LOG$');

SEGMENT_NAME         TABLESPACE_NAME                    BLOCKS    Size Mb
-------------------- ------------------------------ ---------- ----------
FGA_LOG$             AUDIT_DATA                              8      .0625
3. In FGA we can enable audit on the particular column of a table for specifc statement. So let's create a table in testaudit user.

SQL> DEF
DEFINE _DATE          = "14-AUG-25" (CHAR)
DEFINE _CONNECT_IDENTIFIER = "orclpdb" (CHAR)
DEFINE _USER           = "TESTAUDIT" (CHAR)
DEFINE _PRIVILEGE      = "" (CHAR)
DEFINE _SQLPLUS_RELEASE = "1927000000" (CHAR)
DEFINE _EDITOR         = "vi" (CHAR)
DEFINE _O_VERSION      = "Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.27.0.0.0" (CHAR)
DEFINE _O_RELEASE      = "1927000000" (CHAR)
SQL>
SQL> CREATE TABLE  employee (
    emp_id     NUMBER,
    emp_name   VARCHAR2(50),
    salary     NUMBER
);

Table created.

SQL> INSERT INTO  employee VALUES (1, 'Alice',  9000);

1 row created.

SQL> INSERT INTO  employee VALUES (2, 'Bob',   15000);

1 row created.

SQL> INSERT INTO  employee VALUES (3, 'Carol', 20000);

1 row created.

SQL> COMMIT;

Commit complete.

SQL> SELECT * from employee;

    EMP_ID EMP_NAME                                               SALARY
---------- -------------------------------------------------- ----------
         1 Alice                                                    9000
         2 Bob                                                     15000
         3 Carol                                                   20000

SQL>
4. Now enable the auditing on SALARY column of the EMPLOYEE table.

SQL> BEGIN
  dbms_fga.add_policy(
    object_schema   => 'TESTAUDIT',
    object_name     => 'EMPLOYEE',
    policy_name     => 'DML_AUDIT',
    audit_condition => NULL, -- NULL means all rows
    audit_column    => NULL, -- NULL means all columns
    statement_types => 'INSERT,UPDATE,DELETE',
    enable          => TRUE
  );
END;
/

PL/SQL procedure successfully completed.

SQL>
SQL> SET LINESIZE 333 PAGESIZE 333
SQL> COLUMN policy_owner FORMAT A20
SQL> COLUMN policy_column FORMAT A10
SQL> COLUMN object_name FORMAT A15
SQL> COLUMN object_schema FORMAT A20
SQL> COLUMN policy_name FORMAT A30
SQL> SELECT object_schema,
            object_name,
            policy_owner,
            policy_name,
            policy_column,
            sel,
            ins,
            upd,
            del
     FROM dba_audit_policies;

OBJECT_SCHEMA        OBJECT_NAME     POLICY_OWNER         POLICY_NAME                    POLICY_COL SEL INS UPD DEL
-------------------- --------------- -------------------- ------------------------------ ---------- --- --- --- ---
TESTAUDIT            EMPLOYEE          SYS                  DML_AUDIT                                 NO  YES YES YES

5. Now do some DML operation on EMPLOYEE table to test the auditing.

SQL> DEF
DEFINE _DATE           = "14-AUG-25" (CHAR)
DEFINE _CONNECT_IDENTIFIER = "orclpdb" (CHAR)
DEFINE _USER           = "TESTAUDIT" (CHAR)
DEFINE _PRIVILEGE      = "" (CHAR)
DEFINE _SQLPLUS_RELEASE = "1927000000" (CHAR)
DEFINE _EDITOR         = "vi" (CHAR)
DEFINE _O_VERSION      = "Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.27.0.0.0" (CHAR)
DEFINE _O_RELEASE      = "1927000000" (CHAR)
SQL>
SQL> INSERT INTO employee VALUES (4, 'Dave', 5000);

1 row created.

SQL> UPDATE employee SET salary = 1800 WHERE emp_id = 1;

1 row updated.

SQL> DELETE FROM employee WHERE emp_id = 2;

1 row deleted.

SQL> SELECT *
     FROM employee
     WHERE emp_id = 3;

    EMP_ID EMP_NAME        SALARY
---------- ----------  ----------
         3 Carol            20000
6. Now check the captured audit data.

SQL> DEF
DEFINE _DATE           = "14-AUG-25" (CHAR)
DEFINE _CONNECT_IDENTIFIER = "orclpdb" (CHAR)
DEFINE _USER           = "SYS" (CHAR)
DEFINE _PRIVILEGE      = "AS SYSDBA" (CHAR)
DEFINE _SQLPLUS_RELEASE = "1927000000" (CHAR)
DEFINE _EDITOR         = "vi" (CHAR)
DEFINE _O_VERSION      = "Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.27.0.0.0" (CHAR)
DEFINE _O_RELEASE      = "1927000000" (CHAR)
SQL>
SQL> SET LINESIZE 333 PAGESIZE 333
SQL> COLUMN db_user FORMAT A20
SQL> COLUMN sql_text FORMAT A50
SQL> COLUMN extended_timestamp FORMAT A50
SQL> SELECT
    db_user,
    object_name,
    statement_type,
    sql_text,
    extended_timestamp
FROM
    dba_fga_audit_trail
WHERE
    object_name = 'EMPLOYEE'
ORDER BY extended_timestamp DESC;

DB_USER              OBJECT_NAME     STATEME  SQL_TEXT                                             EXTENDED_TIMESTAMP
-------------------- --------------- -------  --------------------------------------------------   -------------------------------------
TESTAUDIT            EMPLOYEE          DELETE  DELETE FROM  EMPLOYEE WHERE emp_id = 2               14-AUG-25 04.33.50.107692 PM +05:30
TESTAUDIT            EMPLOYEE          UPDATE  UPDATE  EMPLOYEE SET salary = 1800 WHERE emp_id = 1  14-AUG-25 04.33.35.071285 PM +05:30
TESTAUDIT            EMPLOYEE          INSERT  INSERT INTO  EMPLOYEE VALUES (4, 'Dave', 5000)       14-AUG-25 04.33.26.467118 PM +05:30
7. We can use below statements to enable,disable & drop FGA policy.


==> To enable FGA policy.

BEGIN DBMS_FGA.ENABLE_POLICY( object_schema => 'TESTAUDIT', object_name => 'EMPLOYEE', policy_name => 'DML_AUDIT' ); END; /

==> To disable FGA policy.

BEGIN DBMS_FGA.DISABLE_POLICY( object_schema => 'TESTAUDIT', object_name => 'EMPLOYEE', policy_name => 'DML_AUDIT' ); END; /

==> To drop FGA policy.

BEGIN DBMS_FGA.DROP_POLICY( object_schema => 'TESTAUDIT', object_name => 'EMPLOYEE', policy_name => 'DML_AUDIT' ); END; /

Now If we need to purge the FGA audit data. We can follow the below steps and by using DBMS_AUDIT_MGMT package.

1. Now first check the current audit records.


SQL>  SELECT COUNT(*) FROM dba_fga_audit_trail;

  COUNT(*)
----------
         5

SQL> SELECT COUNT(*) FROM dba_fga_audit_trail WHERE timestamp < SYSTIMESTAMP -5;

  COUNT(*)
----------
         3
        
2. Now set LAST_ARCHIVE_TIMESTAMP parameter and check the same.

SQL> BEGIN
  DBMS_AUDIT_MGMT.SET_LAST_ARCHIVE_TIMESTAMP(
    audit_trail_type => DBMS_AUDIT_MGMT.AUDIT_TRAIL_FGA_STD,
    last_archive_time => SYSTIMESTAMP - 5
  );
END;
/

PL/SQL procedure successfully completed.

SQL>

SQL> COLUMN audit_trail FORMAT A20
SQL> COLUMN last_archive_ts FORMAT A40
SQL> SELECT * FROM dba_audit_mgmt_last_arch_ts;

AUDIT_TRAIL          RAC_INSTANCE LAST_ARCHIVE_TS                          DATABASE_ID CONTAINER_GUID
-------------------- ------------ ---------------------------------------- ----------- ---------------------------------
FGA AUDIT TRAIL                 0 14-AUG-25 07.47.58.000000 PM +00:00       1593504508 2C3D6BACF692345BE0633350A8C050ED
STANDARD AUDIT TRAIL            0 03-AUG-25 07.46.26.000000 PM +00:00       1593504508 2C3D6BACF692345BE0633350A8C050ED

3. Now purge the audit records older than 5 days.

SQL> BEGIN
  DBMS_AUDIT_MGMT.CLEAN_AUDIT_TRAIL(
    audit_trail_type  => DBMS_AUDIT_MGMT.AUDIT_TRAIL_FGA_STD,
    use_last_arch_timestamp => TRUE
  );
END;
/
PL/SQL procedure successfully completed.

SQL>
        
4. Now again verify the current audit records.

SQL> SELECT COUNT(*) FROM dba_fga_audit_trail;

  COUNT(*)
----------
         2

SQL> SELECT COUNT(*) FROM dba_fga_audit_trail WHERE timestamp < SYSTIMESTAMP -5;

  COUNT(*)
----------
         0

SQL>

SQL>        
5. You can also use delete or truncate statement on sys.fga_log$ table to purge the audit records like below.

==> To purge 30 days older records.

SQL> DELETE FROM sys.fga_log$ WHERE ntimestamp# < SYSTIMESTAMP - INTERVAL '30' DAY; SQL> COMMIT;

==> To empty the audit record table.

SQL> TRUNCATE TABLE sys.fga_log$;


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

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

Tuesday, August 26, 2025

Oracle Database Auditing || Standard



  • Introduction : Oracle Database Auditing is a crucial tool that helps database administrators monitor and record activities occurring within the database environment. By tracking actions such as data modifications, user access, and system changes, auditing provides a detailed record of who did what and when.

  • Types of Auditing in Oracle:
    1. Mandatory Auditing : Certain critical actions or users (like SYSDBA) are audited by default without configuration, ensuring that highly sensitive operations are always tracked. Mandatory Auditing refers to the automatic auditing of specific database actions related to highly privileged users and system-level operations. These include:
      1. Logons by privileged users such as those connecting with the SYSDBA, SYSOPER, or similar administrative roles.
      2. Startup and shutdown operations of the Oracle instance.
      3. DDL statements and DML operations affecting the data dictionary and audit infrastructure.
      4. Direct interactions with audit-related system tables, such as the unified audit trail tables.
    2. Standard Auditing : This traditional auditing method lets you track specific SQL statements and privileges. You can audit actions like SELECT, INSERT, UPDATE, DELETE, DDL commands, and user logins by enabling audit policies using the AUDIT SQL statement.
    3. Fine-Grained Auditing (FGA): FGA provides detailed auditing by allowing you to define specific conditions on which to audit access. For example, you can audit access to particular columns or rows based on user-defined predicates, making it useful for monitoring sensitive data access.
    4. Unified Auditing : Introduced in Oracle 12c, Unified Auditing consolidates all audit records from different sources into a single, centralized audit trail. It simplifies audit management and improves performance by unifying standard, fine-grained, and other audit records.
    Below Table will give the comparison view for different types of auditing.
    Feature Mandatory Auditing Standard Auditing Fine-Grained Auditing (FGA) Unified Auditing
    Purpose Audit critical system activities and SYSDBA/SYSOPER actions Audit general actions (DML, DDL, logins) Audit access to specific rows/columns based on conditions Consolidates all audit types into one unified audit trail
    Configuration Auto-enabled AUDIT / NOAUDIT DBMS_FGA package CREATE AUDIT POLICY + AUDIT statements
    Granularity System-level Statement-level Row & column with conditions All levels unified
    Where Records Are Stored UNIFIED_AUDIT_TRAIL or OS DBA_AUDIT_TRAIL or OS files DBA_FGA_AUDIT_TRAIL UNIFIED_AUDIT_TRAIL view (secure internal table)
    Available In Both Editions Standard & Enterprise Enterprise Only Enterprise Only
    Disablable No Yes Yes Yes (via policy management)

  • AUDIT_TRAIL Parameter :
  • The AUDIT_TRAIL parameter controls whether and where audit records are stored. It's essential for enabling auditing. Below table will give the view of this parameter value.
    Option Description
    NONE Disables auditing. No audit records are generated.
    OS Audit records are written to operating system files.
    DB Audit records are written to the database table AUD$ in the SYS schema.
    DB,EXTENDED Same as DB, but includes SQL statements and bind variables.
    XML Audit records are written to XML files in the location defined by AUDIT_FILE_DEST.
    XML,EXTENDED Same as XML, but includes SQL text and bind values.

    For mandatory Auditing there is no practical steps as it is enabled by default. So, in this article we will configure the Standard Auditing.

  • Environment:
  • Hostname orcl.oraeasy.com
    Database Name orcldb
    Database Version 19.27
    Database Edition Enterprise Edition

  • Prerequisites:
    • 30 min downtime.
    • Sufficient space at tablespace & OS level for storing aduit records.

  • Now proceed for enabling standard auditing step by step:

1. First we need to set the AUDIT_TRAIL parameter, here we will set this DB,EXTENDED.

==>First Create a pfile:

SQL> SHOW PDBS CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 ORCLPDB READ WRITE NO SQL> SQL> DEF DEFINE _DATE = "30-JUL-25" (CHAR) DEFINE _CONNECT_IDENTIFIER = "orcldc" (CHAR) DEFINE _USER = "SYS" (CHAR) DEFINE _PRIVILEGE = "AS SYSDBA" (CHAR) DEFINE _SQLPLUS_RELEASE = "1927000000" (CHAR) DEFINE _EDITOR = "vi" (CHAR) DEFINE _O_VERSION = "Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production Version 19.27.0.0.0" (CHAR) DEFINE _O_RELEASE = "1927000000" (CHAR) SQL> SQL> CREATE PFILE='/home/oracle/pfileorcl.ora' FROM SPFILE; File created.

==> Now set the AUDIT_TRAIL parameter. It requires Database bounce.

SQL> SHOW PARAMETER audit NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ audit_file_dest string /u01/app/oracle/admin/orcl/adu mp audit_sys_operations boolean TRUE audit_syslog_level string audit_trail string DB unified_audit_common_systemlog string unified_audit_sga_queue_size integer 1048576 unified_audit_systemlog string SQL> SQL> ALTER SYSTEM SET audit_trail=DB, EXTENDED SCOPE=SPFILE; System altered. SQL> SQL> SHUTDOWN IMMEDIATE; Database closed. Database dismounted. ORACLE instance shut down. SQL> SQL> STARTUP ORACLE instance started. Total System Global Area 524284552 bytes Fixed Size 9179784 bytes Variable Size 432013312 bytes Database Buffers 75497472 bytes Redo Buffers 7593984 bytes Database mounted. Database opened. SQL> SQL> SHOW PARAMETER audit NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ audit_file_dest string /u01/app/oracle/admin/orcl/adu mp audit_sys_operations boolean TRUE audit_syslog_level string audit_trail string DB, EXTENDED unified_audit_common_systemlog string unified_audit_sga_queue_size integer 1048576 unified_audit_systemlog string SQL> SQL> SHOW PDBS CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 ORCLPDB READ WRITE NO SQL> SQL> ALTER SESSION SET CONTAINER=ORCLPDB; Session altered. SQL> SQL> SHOW PARAMETER audit NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ audit_file_dest string /u01/app/oracle/admin/orcl/adu mp audit_sys_operations boolean TRUE audit_syslog_level string audit_trail string DB, EXTENDED unified_audit_common_systemlog string unified_audit_sga_queue_size integer 1048576 unified_audit_systemlog string SQL>
2. Now we need to assign a tablespace for storing the audit data by using DBMS_AUDIT_MGMT package. By default it is set to SYSTEM tablespace.


SQL> SET LINESIZE 333 PAGESIZE 333
SQL> COLUMN SEGMENT_NAME FORMAT A20
SQL> SELECT segment_name, tablespace_name, blocks, bytes/1024/1024 "Size Mb"
     FROM dba_segments
     WHERE segment_name IN ('AUD$');

SEGMENT_NAME         TABLESPACE_NAME      BLOCKS    Size Mb
-------------------- -----------------  -------- ----------
AUD$                 SYSTEM                    8      .0625

SQL> COLUMN FILE_NAME FORMAT A80
SQL> SELECT file_name, tablespace_name, bytes/1024/1024, status, autoextensible
     FROM dba_data_files
     WHERE tablespace_name IN ('SYSTEM');

FILE_NAME                                            TABLESPACE_NAME    BYTES/1024/1024 STATUS    AUT
---------------------------------------------------- ------------------ --------------- --------- ---
/u01/app/oracle/oradata/ORCL/orclpdb/system01.dbf    SYSTEM                         680 AVAILABLE YES

SQL> CREATE TABLESPACE audit_data 
     DATAFILE '/u01/app/oracle/oradata/ORCL/orclpdb/audit_data01.dbf' 
     SIZE 1G AUTOEXTEND ON;

Tablespace created.

SQL> SELECT file_name, tablespace_name, bytes/1024/1024, status, autoextensible
     FROM dba_data_files
     WHERE tablespace_name IN ('AUDIT_DATA');

FILE_NAME                                                TABLESPACE_NAME   BYTES/1024/1024 STATUS    AUT
-------------------------------------------------------- ----------------- --------------- --------- ---
/u01/app/oracle/oradata/ORCL/orclpdb/audit_data01.dbf    AUDIT_DATA                   1024 AVAILABLE YES

SQL>
SQL> BEGIN
         dbms_audit_mgmt.set_audit_trail_location(
             audit_trail_type => dbms_audit_mgmt.audit_trail_aud_std,
             audit_trail_location_value => 'AUDIT_DATA');
     END;
     /
PL/SQL procedure successfully completed.

SQL> SELECT segment_name, tablespace_name, blocks, bytes/1024/1024 "Size Mb"
     FROM dba_segments
     WHERE segment_name IN ('AUD$');

SEGMENT_NAME         TABLESPACE_NAME       BLOCKS    Size Mb
-------------------- ----------------- ---------- ----------
AUD$                 AUDIT_DATA                 8      .0625
3. Now we need to enable the audit policy. Here we will enable DDL auditing.


SQL> SHOW PDBS

    CON_ID CON_NAME                       OPEN MODE  RESTRICTED
--- ------------------------------ ---------- ----------
         2 PDB$SEED                       READ ONLY  NO
         3 ORCLPDB                        READ WRITE NO
SQL>

SQL> ALTER SESSION SET CONTAINER=ORCLPDB;

Session altered.

SQL> SELECT COUNT(*) FROM dba_audit_trail;

  COUNT(*)
----------
         0

SQL> AUDIT TABLE BY ACCESS;

Audit succeeded.

SQL> AUDIT ALTER TABLE BY ACCESS;

Audit succeeded.

SQL>  AUDIT INDEX BY ACCESS;

Audit succeeded.

SQL> AUDIT PROCEDURE BY ACCESS;

Audit succeeded.

SQL> AUDIT VIEW BY ACCESS;

Audit succeeded.

SQL> AUDIT TRIGGER BY ACCESS;

Audit succeeded.

SQL>
4. Now check the enabled audit statements.

SQL> SET LINESIZE 333 PAGESIZE 333
SQL> SELECT audit_option, success, failure
     FROM dba_stmt_audit_opts;

AUDIT_OPTION                             SUCCESS    FAILURE
---------------------------------------- ---------- ----------
TABLE                                    BY ACCESS  BY ACCESS
VIEW                                     BY ACCESS  BY ACCESS
PROCEDURE                                BY ACCESS  BY ACCESS
TRIGGER                                  BY ACCESS  BY ACCESS
ALTER ANY TABLE                          BY ACCESS  BY ACCESS
INDEX                                    BY ACCESS  BY ACCESS
ALTER TABLE                              BY ACCESS  BY ACCESS
CREATE ANY INDEX                         BY ACCESS  BY ACCESS
DROP ANY INDEX                           BY ACCESS  BY ACCESS

9 rows selected.

SQL>

5. Now create a test user to test the auditing.

SQL> CREATE USER testaudit IDENTIFIED BY TesT##123;

User created.

SQL> GRANT connect, resource TO testaudit;

Grant succeeded.

SQL> GRANT unlimited tablespace TO testaudit;

Grant succeeded.

SQL> GRANT create view TO testaudit;;

Grant succeeded

6. Now login with test user and do some DDL operations.


SQL> DEF
DEFINE _DATE           = "30-JUL-25" (CHAR)
DEFINE _CONNECT_IDENTIFIER = "orclpdb" (CHAR)
DEFINE _USER           = "TESTAUDIT" (CHAR)
DEFINE _PRIVILEGE      = "" (CHAR)
DEFINE _SQLPLUS_RELEASE = "1927000000" (CHAR)
DEFINE _EDITOR         = "vi" (CHAR)
DEFINE _O_VERSION      = "Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.27.0.0.0" (CHAR)
DEFINE _O_RELEASE      = "1927000000" (CHAR)
SQL>
SQL> CREATE TABLE company (emp_id INT, name VARCHAR2(255));

Table created.

SQL> DROP TABLE company;

Table dropped.

SQL> CREATE TABLE company (emp_id INT, name VARCHAR2(255));

Table created.

SQL> ALTER TABLE COMPANY DROP COLUMN city;

Table altered.

SQL> ALTER TABLE company ADD city VARCHAR2(20);

Table altered.

SQL> CREATE INDEX testidx ON company(city);

Index created.

SQL> DROP INDEX testidx;

Index dropped.

SQL> CREATE INDEX testidx ON company (city);

Index created.

SQL> ALTER INDEX testidx REBUILD;

Index altered.

SQL> ALTER INDEX testidx RENAME TO testidx_renamed;

Index altered.

SQL> CREATE VIEW comview AS SELECT * FROM company;

View created.

SQL> CREATE OR REPLACE TRIGGER trg_before_insert_company
	 BEFORE INSERT ON company
	 FOR EACH ROW
 	 BEGIN
 	 :NEW.name := UPPER(:NEW.name);
   	 END;
	 / 

Trigger created.

SQL> CREATE OR REPLACE PROCEDURE add_employee (
 	 p_emp_id IN NUMBER,
 	 p_name   IN VARCHAR2
	)
	IS
	BEGIN
  	INSERT INTO company (emp_id, name)
  	VALUES (p_emp_id, p_name);
 	DBMS_OUTPUT.PUT_LINE('Employee added: ' || p_emp_id || ' - ' || p_name);
    EXCEPTION
  	WHEN DUP_VAL_ON_INDEX THEN
    DBMS_OUTPUT.PUT_LINE('Error: Employee with ID '   3  || p_emp_id || ' already exists.');
  	WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('Unexpected error: ' || SQLERRM);
	END;
	/

Procedure created.
7. Now check the captured audit data.

SQL> SET LINESIZE 150 PAGESIZE 100
SQL> COLUMN username FORMAT A15
SQL> COLUMN owner FORMAT A15
SQL> COLUMN obj_name FORMAT A25
SQL> COLUMN action_name FORMAT A20
SQL> COLUMN extended_timestamp FORMAT A35
SQL> SELECT username, extended_timestamp, owner, obj_name, action_name
     FROM dba_audit_trail
     ORDER BY extended_timestamp;

USERNAME             EXTENDED_TIMESTAMP                       OWNER                OBJ_NAME                                 ACTION_NAME
-------------------- ---------------------------------------- -------------------- ---------------------------------------- ----------------------------
TESTAUDIT            30-JUL-25 09.20.09.495217 PM +05:30      TESTAUDIT            COMPANY                                  CREATE TABLE
TESTAUDIT            30-JUL-25 09.22.34.542501 PM +05:30      TESTAUDIT            COMPANY                                  DROP TABLE
TESTAUDIT            30-JUL-25 09.22.51.495226 PM +05:30      TESTAUDIT            COMPANY                                  CREATE TABLE
TESTAUDIT            30-JUL-25 09.32.34.970492 PM +05:30      TESTAUDIT            COMPANY                                  ALTER TABLE
TESTAUDIT            30-JUL-25 09.35.11.064356 PM +05:30      TESTAUDIT            COMPANY                                  ALTER TABLE
TESTAUDIT            30-JUL-25 09.39.03.514319 PM +05:30      TESTAUDIT            TESTIDX                                  DROP INDEX
TESTAUDIT            30-JUL-25 09.39.29.215912 PM +05:30      TESTAUDIT            TESTIDX                                  CREATE INDEX
TESTAUDIT            30-JUL-25 09.42.37.492291 PM +05:30      TESTAUDIT            TESTIDX                                  CREATE INDEX
TESTAUDIT            30-JUL-25 09.43.00.302514 PM +05:30      TESTAUDIT            TESTIDX                                  ALTER INDEX
TESTAUDIT            30-JUL-25 10.09.23.738087 PM +05:30      TESTAUDIT            COMVIEW                                  CREATE VIEW
TESTAUDIT            30-JUL-25 10.09.42.569093 PM +05:30      TESTAUDIT            COMVIEW                                  CREATE VIEW
TESTAUDIT            30-JUL-25 10.12.37.288751 PM +05:30      TESTAUDIT            TRG_BEFORE_INSERT_COMPANY                CREATE TRIGGER
TESTAUDIT            30-JUL-25 10.13.21.758069 PM +05:30      TESTAUDIT            ADD_EMPLOYEE                             CREATE PROCEDURE

13 rows selected.
8. Now in the similar way we can enable DML audit also. Refer below.

SQL> AUDIT INSERT, UPDATE, DELETE ON testaudit.company BY ACCESS;

Audit succeeded.


==> Now check the DML audit policy.

SQL> SELECT owner, object_name, ins, upd, del FROM dba_obj_audit_opts WHERE owner = 'TESTAUDIT' AND object_name = 'COMPANY'; OWNER OBJECT_NAME INS UPD DEL -------------------- -------------------- --------- --------- --------- TESTAUDIT COMPANY A/A A/A A/A SQL>
9. If we need to disable auditing for any particular object, we can do using noaudit statement.

SQL> NOAUDIT INSERT, UPDATE, DELETE ON testaudit.company;

Noaudit succeeded.

SQL>
SQL> NOAUDIT VIEW;

Noaudit succeeded.

SQL>

Now If we need to purge the audit data. We can follow the below steps and by using DBMS_AUDIT_MGMT package.

1. Now first check the current audit records.

SQL> SELECT COUNT(*) FROM dba_audit_trail;

  COUNT(*)
----------
        15

SQL> SELECT COUNT(*) FROM dba_audit_trail WHERE  timestamp < SYSTIMESTAMP - 10;

  COUNT(*)
----------
        13
        
2. Now set LAST_ARCHIVE_TIMESTAMP parameter and check the same.

SQL> BEGIN
DBMS_AUDIT_MGMT.set_last_archive_timestamp(
audit_trail_type => DBMS_AUDIT_MGMT.AUDIT_TRAIL_AUD_STD,
last_archive_time => SYSTIMESTAMP-10);
END;
/ 

PL/SQL procedure successfully completed.

SQL>

SQL> COLUMN audit_trail FORMAT A20
SQL> COLUMN last_archive_ts FORMAT A40
SQL> SELECT * FROM dba_audit_mgmt_last_arch_ts;

AUDIT_TRAIL          RAC_INSTANCE LAST_ARCHIVE_TS                          DATABASE_ID CONTAINER_GUID
-------------------- ------------ ---------------------------------------- ----------- ---------------------------------
FGA AUDIT TRAIL                 0 31-JUL-25 10.56.47.000000 PM +00:00       1593504508 2C3D6BACF692345BE0633350A8C050ED
STANDARD AUDIT TRAIL            0 03-AUG-25 07.46.26.000000 PM +00:00       1593504508 2C3D6BACF692345BE0633350A8C050ED

3. Now purge the audit records older than 10 days.

SQL> BEGIN
DBMS_AUDIT_MGMT.clean_audit_trail(
audit_trail_type => DBMS_AUDIT_MGMT.AUDIT_TRAIL_AUD_STD,
use_last_arch_timestamp => TRUE);
END;
/ 

PL/SQL procedure successfully completed.

SQL>
        
4. Now again verify the current audit records.

SQL> SELECT COUNT(*) FROM dba_audit_trail;

  COUNT(*)
----------
         2

SQL> SELECT COUNT(*) FROM dba_audit_trail WHERE timestamp < SYSTIMESTAMP - 10;

  COUNT(*)
----------
         0

SQL>        
5. You can also use delete or truncate statement on sys.aud$ table to purge the audit records like below.

==> To purge 30 days older records.

SQL> DELETE FROM sys.aud$ WHERE ntimestamp# < SYSTIMESTAMP - INTERVAL '30' DAY; SQL> COMMIT;

==> To empty the audit record table.

SQL> TRUNCATE TABLE sys.aud$;


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

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

Tuesday, August 19, 2025

OEM 13.5 Installation on Linux



  • Introduction: Oracle Enterprise Manager (OEM) is Oracle’s unified management platform for overseeing the full Oracle technology stack. OEM enables administrators to monitor, configure, and optimize Oracle Databases, Oracle Middleware, Oracle Applications, and Oracle Engineered Systems. It streamlines critical operations such as patching, configuration management, performance diagnostics, and lifecycle automation, ensuring that Oracle workloads remain secure, reliable, and high-performing. In this article, we will see how to configure the OEM on Linux environment step by step.

  • Prerequisites: Below are the minimum requirements for Linux environment.
    • CPU - 2core
    • RAM - 10GB
    • Disk space - 45GB (/u01) & 50GB (/oem)
    • OEM Binary. Download here.
    • Must have root user or sudo access.
    • Disable the firewall.
  • Environment:
  • Hostname oem.oraeasy.com/192.168.1.33
    OS OL 7.3
    OEM Version 13c Release 5 (13.5)
    OMS Home /oem/app/oracle/middleware
    Agent Base /oem/app/oracle/agent
    Repository Database Name OEMDB
    Database Version 19.27.0
    Oracle Home /u01/app/oracle/product/19c/db_home

  • Now let's proceed to configure the OEM step by step:

1. First we need to verify that the database must have sufficient redo log groups to avoid log file sync wait during installation, if not then add accordingly.

SQL> select name,open_mode,log_mode from v$database;

NAME      OPEN_MODE            LOG_MODE
--------- -------------------- ------------
OEMDB     READ WRITE           ARCHIVELOG

SQL> SELECT group#, status,bytes/1024/1024 AS size_mb FROM v$log ORDER BY group#; 

    GROUP# STATUS	size_mb
---------- ---------	------
         1 INACTIVE	200
         2 CURRENT	200
         3 INACTIVE	200

SQL> ALTER DATABASE ADD LOGFILE GROUP 4 '/u01/app/oracle/oradata/OEMDB/redo04.log' SIZE 1G;

Database altered.

SQL> ALTER DATABASE ADD LOGFILE GROUP 5 '/u01/app/oracle/oradata/OEMDB/redo05.log' SIZE 1G;

Database altered.

SQL> ALTER DATABASE ADD LOGFILE GROUP 6 '/u01/app/oracle/oradata/OEMDB/redo06.log' SIZE 1G;

Database altered.

SQL> SELECT group#, status FROM v$log ORDER BY group#; 

    GROUP# STATUS
---------- ----------------
         1 INACTIVE
         2 CURRENT
         3 INACTIVE
         4 UNUSED
         5 UNUSED
         6 UNUSED

6 rows selected.

SQL> ALTER DATABASE DROP LOGFILE GROUP 1;

Database altered.

SQL> alter system switch logfile;

System altered.

SQL> SELECT group#, status FROM v$log ORDER BY group#;

    GROUP# STATUS
---------- ----------------
         2 ACTIVE
         3 INACTIVE
         4 ACTIVE
         5 ACTIVE
         6 CURRENT

SQL> ALTER DATABASE DROP LOGFILE GROUP 3;

Database altered.

SQL> alter system checkpoint;

System altered.

SQL> SELECT group#, status FROM v$log ORDER BY group#;

    GROUP# STATUS
---------- ----------------
         2 INACTIVE
         4 INACTIVE
         5 CURRENT
         6 INACTIVE

SQL> ALTER DATABASE DROP LOGFILE GROUP 2;

Database altered.

SQL> ALTER DATABASE ADD LOGFILE GROUP 7 '/u01/app/oracle/oradata/OEMDB/redo07.log' SIZE 1G;

Database altered.

SQL> SELECT group#, status FROM v$log ORDER BY group#;

    GROUP# STATUS
---------- ----------------
         4 INACTIVE
         5 CURRENT
         6 INACTIVE
         7 UNUSED

2. Now verify TNS servivce and sys user password.

[oracle@oem ~]$ tnsping oemdb

TNS Ping Utility for Linux: Version 19.0.0.0.0 - Production on 16-AUG-2025 12:25:05

Copyright (c) 1997, 2025, Oracle.  All rights reserved.

Used parameter files:


Used TNSNAMES adapter to resolve the alias
Attempting to contact (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = oem.oraeasy.com)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = oemdb)))
OK (10 msec)
[oracle@oem ~]$
[oracle@oem ~]$ sqlplus sys@oemdb as sysdba

SQL*Plus: Release 19.0.0.0.0 - Production on Sat Aug 16 12:25:09 2025
Version 19.27.0.0.0

Copyright (c) 1982, 2024, Oracle.  All rights reserved.

Enter password:

Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.27.0.0.0

SQL> def
DEFINE _DATE           = "16-AUG-25" (CHAR)
DEFINE _CONNECT_IDENTIFIER = "oemdb" (CHAR)
DEFINE _USER           = "SYS" (CHAR)
DEFINE _PRIVILEGE      = "AS SYSDBA" (CHAR)
DEFINE _SQLPLUS_RELEASE = "1927000000" (CHAR)
DEFINE _EDITOR         = "vi" (CHAR)
DEFINE _O_VERSION      = "Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.27.0.0.0" (CHAR)
DEFINE _O_RELEASE      = "1927000000" (CHAR)
SQL>
SQL> select name,open_mode from v$database;

NAME      OPEN_MODE
--------- --------------------
OEMDB     READ WRITE
3. Now we need to change some parameter in Repository database for OEM. Create a pfile for backup.

SQL> select name,open_mode,log_mode from v$database;

NAME      OPEN_MODE            LOG_MODE
--------- -------------------- ------------
OEMDB     READ WRITE           ARCHIVELOG

SQL> create pfile='/home/oracle/oemdb.ora' from spfile;

File created.

SQL> show parameter _allow_insert_with_update_check
SQL> show parameter session_cached_cursors

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
session_cached_cursors               integer     50

SQL> show parameter shared_pool_size

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
shared_pool_size                     big integer 0

SQL> show parameter processes

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
aq_tm_processes                      integer     1
db_writer_processes                  integer     1
gcs_server_processes                 integer     0
global_txn_processes                 integer     1
job_queue_processes                  integer     40
log_archive_max_processes            integer     4
processes                            integer     300
SQL>
SQL> show parameter "_allow_insert_with_update_check"

SQL> alter system set "_allow_insert_with_update_check"=true scope=both;

System altered.

SQL> alter system set session_cached_cursors=200 scope=spfile;

System altered.

SQL> alter system set shared_pool_size=600M scope=spfile;

System altered.

SQL> show parameter pga

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
pga_aggregate_limit                  big integer 2G
pga_aggregate_target                 big integer 0
SQL>
SQL> alter system set processes=600 scope=spfile;

System altered.

SQL> shut immediate;
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL>
SQL> startup
ORACLE instance started.

Total System Global Area 1979711112 bytes
Fixed Size                  8941192 bytes
Variable Size            1358954496 bytes
Database Buffers          603979776 bytes
Redo Buffers                7835648 bytes
Database mounted.
Database opened.
SQL>
SQL> show parameter _allow_insert_with_update_check

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
_allow_insert_with_update_check      boolean     TRUE

SQL>  show parameter session_cached_cursors

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
session_cached_cursors               integer     200

SQL>  show parameter shared_pool_size

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
shared_pool_size                     big integer 608M
SQL>
SQL> show parameter processes

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
aq_tm_processes                      integer     1
db_writer_processes                  integer     1
gcs_server_processes                 integer     0
global_txn_processes                 integer     1
job_queue_processes                  integer     40
log_archive_max_processes            integer     4
processes                            integer     600
4. Now create required directory for OMS & Agent and also place the OEM binary in /oem/software/.

[oracle@oem ~]$ mkdir -p /oem/app/oracle/middleware
[oracle@oem ~]$ mkdir -p /oem/app/oracle/agent
[oracle@oem ~]$
[oracle@oem ~]$ ll /oem/app/oracle/
total 0
drwxr-xr-x. 2 oracle oinstall 6 Aug 16 12:18 agent
drwxr-xr-x. 2 oracle oinstall 6 Aug 16 12:18 middleware
[oracle@oem ~]$
[oracle@oem ~]$ cd /oem/software/
[oracle@oem software]$
[oracle@oem software]$ ls -lrth
total 8.0G
-rwxrwxr-x. 1 oracle oinstall 1.5G Aug 16 12:19 em13500_linux64.bin
-rwxrwxr-x. 1 oracle oinstall 1.8G Aug 16 12:19 em13500_linux64-2.zip
-rwxrwxr-x. 1 oracle oinstall 2.0G Aug 16 12:19 em13500_linux64-3.zip
-rwxrwxr-x. 1 oracle oinstall 1.4G Aug 16 12:19 em13500_linux64-4.zip
-rwxrwxr-x. 1 oracle oinstall 1.4G Aug 16 12:19 em13500_linux64-5.zip
[oracle@oem software]$
5. Now we need to start the installation. Make sure that /tmp has 12GB free space. If not then provide a temporary location where 12GB free space is there.

[oracle@oem software]$ pwd
/oem/software
[oracle@oem software]$
[oracle@oem software]$ ./em13500_linux64.bin
ERROR: Temporary directory /tmp does not have enough free space. At least 12289 MB of free space are required.
Please input another directory or [Exit]: /u01/software/temp
Launcher log file is /u01/software/temp/OraInstall2025-08-16_12-28-40PM/launcher2025-08-16_12-28-40PM.log.
Extracting the installer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  . . . . . . .
. . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . Done Checking monitor: must be configured to display at least 256 colors. Actual 16777216 Passed Checking swap space: must be greater than 512 MB. Actual 4095 MB Passed Checking if this platform requires a 64-bit JVM. Actual 64 Passed (64-bit not required) Preparing to launch the Oracle Universal Installer from /u01/software/temp/OraInstall2025-08-16_12-28-40PM ScratchPathValue :/u01/software/temp/OraInstall2025-08-16_12-28-40PM Aug 16, 2025 12:34:18 PM org.apache.sshd.common.io.DefaultIoServiceFactoryFactory getIoServiceProvider INFO: No detected/configured IoServiceFactoryFactory using Nio2ServiceFactoryFactory .......................................................................................

6. Now OEM GUI installer window will open. Follow the below steps.

Select Advanced Install & click Next.

Select Skip & click Next.

Click on Ignore to ignore the warnings.

Click Next.

Provide OMS Home, Agent Base directory and OEM server hostname. Then click Next.

Click Next.

Provide the password & click Next.

Provide the Repository Database details & click Next.

Click on Auto Fix.

Click Next.

Click Ok.

Provide the SYSMAN & Agent Registration password. Then click Next.

Click Next.

Click Next.

Review the details & click Install.

Note: The entire installation process may take 5-6 hrs. Keep monitoring the database alert log to avoid any faliure.

Keep Monitoting the progress & related logs.

If you encountered that the installation gets hung like below. Then check the objects stats of SYSMAN schema and gather its stats. Steps given below:


==> Check if stats are locked or not.

SQL> SELECT stattype_locked FROM dba_tab_statistics WHERE owner = 'SYSMAN'; STATT ----- ALL ALL ALL ALL ALL ALL ALL ALL ALL ALL ALL .... .... .... 5930 rows selected.

==> Unlock the stats & do stat gather.

SQL> EXEC DBMS_STATS.unlock_schema_stats('SYSMAN'); PL/SQL procedure successfully completed. SQL> SELECT stattype_locked FROM dba_tab_statistics WHERE owner = 'SYSMAN'; STATT ----- .... .... .... 5930 rows selected. SQL> EXEC DBMS_STATS.gather_schema_stats('SYSMAN'); PL/SQL procedure successfully completed.

Wait for sometime & installation will move further.

Execute the script from root user. Then click Ok.


[root@oem ~]# /oem/app/oracle/middleware/allroot.sh

Starting to execute allroot.sh .........

Starting to execute /oem/app/oracle/middleware/root.sh ......
Check /oem/app/oracle/middleware/install/root_oem.oraeasy.com_2025-08-16_18-19-43.log for the output of root script

Finished product-specific root actions.
/etc exist
Finished execution of  /oem/app/oracle/middleware/root.sh ......

Starting to execute /oem/app/oracle/agent/agent_13.5.0.0.0/root.sh ......

Finished product-specific root actions.
/etc exist
Finished execution of  /oem/app/oracle/agent/agent_13.5.0.0.0/root.sh ......
[root@oem ~]#

Now installation got completed. Review the details & click Close.
7. Now check the OMS & Agent status.

[oracle@oem ~]$ cd /oem/app/oracle/middleware/bin
[oracle@oem bin]$ ./emctl status oms
Oracle Enterprise Manager Cloud Control 13c Release 5
Copyright (c) 1996, 2021 Oracle Corporation.  All rights reserved.
WebTier is Up
Oracle Management Server is Up
JVMD Engine is Up
[oracle@oem bin]$
[oracle@oem bin]$ ./emctl status oms -details
Oracle Enterprise Manager Cloud Control 13c Release 5
Copyright (c) 1996, 2021 Oracle Corporation.  All rights reserved.
Enter Enterprise Manager Root (SYSMAN) Password :
Console Server Host        : oem.oraeasy.com
HTTP Console Port          : 7788
HTTPS Console Port         : 7803
HTTP Upload Port           : 4889
HTTPS Upload Port          : 4903
EM Instance Home           : /oem/app/oracle/gc_inst/em/EMGC_OMS1
OMS Log Directory Location : /oem/app/oracle/gc_inst/em/EMGC_OMS1/sysman/log
OMS is not configured with SLB or virtual hostname
Agent Upload is locked.
OMS Console is locked.
Active CA ID: 1
Console URL: https://oem.oraeasy.com:7803/em
Upload URL: https://oem.oraeasy.com:4903/empbs/upload

WLS Domain Information
Domain Name            : GCDomain
Admin Server Host      : oem.oraeasy.com
Admin Server HTTPS Port: 7102
Admin Server is RUNNING

Oracle Management Server Information
Managed Server Instance Name: EMGC_OMS1
Oracle Management Server Instance Host: oem.oraeasy.com
WebTier is Up
Oracle Management Server is Up
JVMD Engine is Up
[oracle@oem bin]$

[oracle@oem bin]$ cd /oem/app/oracle/agent/agent_13.5.0.0.0/bin
[oracle@oem bin]$ ./emctl status agent
Oracle Enterprise Manager Cloud Control 13c Release 5
Copyright (c) 1996, 2021 Oracle Corporation.  All rights reserved.
---------------------------------------------------------------
Agent Version          : 13.5.0.0.0
OMS Version            : 13.5.0.0.0
Protocol Version       : 12.1.0.1.0
Agent Home             : /oem/app/oracle/agent/agent_inst
Agent Log Directory    : /oem/app/oracle/agent/agent_inst/sysman/log
Agent Binaries         : /oem/app/oracle/agent/agent_13.5.0.0.0
Core JAR Location      : /oem/app/oracle/agent/agent_13.5.0.0.0/jlib
Agent Process ID       : 3038
Parent Process ID      : 2742
Agent URL              : https://oem.oraeasy.com:3872/emd/main/
Local Agent URL in NAT : https://oem.oraeasy.com:3872/emd/main/
Repository URL         : https://oem.oraeasy.com:4903/empbs/upload
Started at             : 2025-08-16 19:21:59
Started by user        : oracle
Operating System       : Linux version 4.1.12-61.1.18.el7uek.x86_64 (amd64)
Number of Targets      : 35
Last Reload            : (none)
Last successful upload                       : 2025-08-16 20:04:16
Last attempted upload                        : 2025-08-16 20:04:16
Total Megabytes of XML files uploaded so far : 0.14
Number of XML files pending upload           : 0
Size of XML files pending upload(MB)         : 0
Available disk space on upload filesystem    : 60.96%
Collection Status                            : Collections enabled
Heartbeat Status                             : Ok
Last attempted heartbeat to OMS              : 2025-08-16 20:06:20
Last successful heartbeat to OMS             : 2025-08-16 20:06:20
Next scheduled heartbeat to OMS              : 2025-08-16 20:07:20

---------------------------------------------------------------
Agent is Running and Ready
[oracle@oem bin]$

8. Now open the below URL & do login with SYSMAN credential.
https://192.168.1.33:7803/em

Provide credential & click Login.

Accept License Agreement.

Welcome Page.

Click on Enterprise --> Summary.


9. Below are the command to start & stop the OEM services. Make sure that Database & Listener services are running.

Set environment.

[oracle@oem ~]$ export OMS_HOME=/oem/app/oracle/middleware [oracle@oem ~]$ export AGENT_HOME=/oem/app/oracle/agent/agent_13.5.0.0.0

To Start.

[oracle@oem ~]$ $OMS_HOME/bin/./emctl start oms [oracle@oem ~]$ $OMS_HOME/bin/./emctl start agent

To Stop.

[oracle@oem ~]$ $OMS_HOME/bin/./emctl stop oms [oracle@oem ~]$ $OMS_HOME/bin/./emctl stop agent
Issue Faced: During installation, we faced issue in starting the OMS services due to library issue. You can refer the below troubleshooting & solution steps if you face the same. Do not close the installer GUI window.
1. In OEM installer log.

INFO: oracle.sysman.top.oms:Copyright (c) 1996, 2021 Oracle Corporation. All rights reserved. 
INFO: oracle.sysman.top.oms:Starting Oracle Management Server... 
INFO: oracle.sysman.top.oms:WebTier Could Not Be Started. 
INFO: oracle.sysman.top.oms:Error Occurred: WebTier Could Not Be Started. 
INFO: oracle.sysman.top.oms:Please check /oem/app/oracle/gc_inst/em/EMGC_OMS1/sysman/log/emctl.log for error details SEVERE: 
	oracle.sysman.top.oms:Starting of OMS failed. 
2. In OHS log.

[oracle@oem bin]$ tail -50 /oem/app/oracle/gc_inst/user_projects/domains/GCDomain/system_components/OHS/ohs_nm.log
2025-08-16 16:16:06  INFO   OHS-0   Domain initialized for /oem/app/oracle/gc_inst/user_projects/domains/GCDomain  
2025-08-16 16:16:07  INFO   OHS-4112   Creating instance ohs1  
2025-08-16 16:16:10  INFO   OHS-4114   Updating instance ohs1  
2025-08-16 17:13:18  INFO   OHS-4018   Starting server ohs1  
2025-08-16 17:13:18  INFO   OHS-0   Running /oem/app/oracle/middleware/ohs/bin/launch httpd -DOHS_MPM_WORKER -d  /oem/app/oracle/gc_inst/user_projects/domains/GCDomain/config/fmwconfig/components/OHS/instances/ohs1 -k start -f  /oem/app/oracle/gc_inst/user_projects/domains/GCDomain/config/fmwconfig/components/OHS/instances/ohs1/httpd.conf  
2025-08-16 17:13:19  INFO   OHS-0   /oem/app/oracle/middleware/ohs/bin/httpd: error while loading shared libraries: libclntshcore.so.12.1: 
cannot open shared object file: No such file or directory

That’s the root cause: OHS (Oracle HTTP Server) cannot find the Oracle client library libclntshcore.so.12.1.

3. Set LD_LIBRARY_PATH in setDomainEnv.sh file.

[oracle@oem bin]$ cat /oem/app/oracle/gc_inst/user_projects/domains/GCDomain/bin/setDomainEnv.sh|grep LD_LIBRARY_PATH
export LD_LIBRARY_PATH=$ORACLE_HOME/lib:$LD_LIBRARY_PATH
4. Link the libclntshcore library file.

[oracle@oem lib]$ ln -s /u01/app/oracle/product/19c/db_home/lib/libclntshcore.so.19.1 libclntshcore.so.12.1
[oracle@oem lib]$ ls -l /oem/app/oracle/middleware/ohs/lib/libclntshcore.so.*
lrwxrwxrwx. 1 oracle oinstall 61 Aug 16 17:56 /oem/app/oracle/middleware/ohs/lib/libclntshcore.so.12.1 -> /u01/app/oracle/product/19c/db_home/lib/libclntshcore.so.19.1
5. Stop & Start the OMS manually.

[oracle@oem lib]$ cd /oem/app/oracle/middleware/bin
[oracle@oem bin]$ ./emctl stop oms -all
Oracle Enterprise Manager Cloud Control 13c Release 5
Copyright (c) 1996, 2021 Oracle Corporation.  All rights reserved.
Stopping Oracle Management Server...
WebTier Could Not Be Stopped
Oracle Management Server Successfully Stopped
AdminServer Failed to be Stopped
Check Admin Server log file for details: /oem/app/oracle/gc_inst/user_projects/domains/GCDomain/servers/EMGC_ADMINSERVER/logs/EMGC_ADMINSERVER.out
Oracle Management Server is Down
JVMD Engine is Down
[oracle@oem bin]$
[oracle@oem bin]$ ./emctl start oms
Oracle Enterprise Manager Cloud Control 13c Release 5
Copyright (c) 1996, 2021 Oracle Corporation.  All rights reserved.
Starting Oracle Management Server...
WebTier Successfully Started
Oracle Management Server Successfully Started
Oracle Management Server is Up
JVMD Engine is Up
[oracle@oem bin]$
6. Last click Retry on installer GUI window.


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

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