Oracle 19c Patching on Linux – Complete Step-by-Step Guide
Learn Oracle 19c patching on Linux with this complete step-by-step guide. Download OPatch, apply Release Updates (RU), verify the patch, and troubleshoot common issues.
A complete production-ready SOP for patching Oracle Database 19c on a standalone Linux server. Covers patch identification, download, pre-patch checks, OPatch upgrade, patch apply, datapatch execution, and full post-patch validation — with real commands, expected outputs, and consultant-level notes for both standard OFA and enterprise custom path conventions.
1. Document Info
| Item | Detail |
|---|---|
| Oracle Version | 19c (19.3 base + applicable RU) |
| OS | Oracle Linux 7.x / RHEL 7.x or 8.x |
| Patch Type | Release Update (RU) — Standalone (Non-RAC) |
| Patching Method | In-place (same ORACLE_HOME) |
| MOS Reference | Doc ID 2694520.1 (19c Patch Advisories) |
| MOS Reference | Doc ID 1410202.1 (OPatch Quick Start) |
2. Path Conventions
Same conventions as SOP 01. Confirm which convention your environment uses before starting. All examples in this SOP use Convention A paths. Substitute with Convention B paths where applicable.
| Item | Convention A | Convention B |
|---|---|---|
| Oracle Base | /u01/app/oracle | /oracle |
| Oracle Home | /u01/app/oracle/product/19.3.0/dbhome_1 | /oracle/RDBMS/19.31 |
| oraInventory | /u01/app/oraInventory | /oracle/oraInventory |
3. Oracle Patching — Concepts You Must Know First
Before touching any patch command, understand these terms. You will use them every time you patch.
| Term | What It Means |
|---|---|
| RU (Release Update) | Quarterly cumulative patch from Oracle. Contains all bug fixes since base release. Always prefer RU over individual one-off patches. Example: 19.22 RU |
| RUR (Release Update Revision) | A smaller patch on top of an RU for critical fixes between quarterly cycles. Less common. |
| One-off Patch | A single bug fix patch for a specific issue. Applied on top of RU when a specific bug needs fixing urgently. |
| OPatch | Oracle’s patching utility. All patches are applied and rolled back using OPatch. Lives inside ORACLE_HOME/OPatch. |
| datapatch | A separate Oracle utility that applies SQL-level changes from a patch into the database dictionary. Must be run AFTER OPatch. OPatch patches the binaries, datapatch patches the database internals. |
| Patch Conflict | When two patches modify the same file. OPatch detects this automatically during prereq check. Must be resolved before applying. |
| Rolling Patch | Patching one node at a time in RAC — database stays online. Not applicable for standalone. |
| In-place Patching | Applying the patch directly to the existing ORACLE_HOME. Database must be down. |
| Out-of-place Patching | Installing a new ORACLE_HOME with the patch already applied, then switching the database to it. Database downtime is shorter. Covered separately. |
4. Pre-Patching Checks
⚠️ IMPORTANT: Never start patching without completing all pre-checks. A failed patch mid-way on a production database is a serious incident. 30 minutes on pre-checks prevents hours of rollback.
4.1 — Confirm Current Oracle Version and Patch Level
Why? You need to know exactly what is currently installed before deciding which patch to apply. The patch you download from MOS must be for the exact version currently running.
sqlplus / as sysdba
set linesize 150
set pagesize 50
col banner for a80
-- Shows full Oracle version string
SELECT banner FROM v$version WHERE banner LIKE 'Oracle%';
-- Shows exact version and patch level
SELECT version, version_full FROM v$instance;# Also check via OPatch — shows current patch inventory
su - oracle
$ORACLE_HOME/OPatch/opatch lsinventory
# Quick view of installed patches only
$ORACLE_HOME/OPatch/opatch lsinventory | grep -E "Patch|Oracle Database"4.2 — Confirm OPatch Version and Upgrade if Needed
Why? Every Oracle RU requires a minimum OPatch version. If your OPatch is older than what the patch requires, OPatch will refuse to apply the patch. Always upgrade OPatch FIRST before applying any patch.
su - oracle
# Check current OPatch version
$ORACLE_HOME/OPatch/opatch version📎 How to find required OPatch version: Open the patch README file (inside the patch zip) and look for the line
OPatch version required. Then compare with your current version.
📎 Download latest OPatch: MOS Doc ID 6880880.1 → Download patch 6880880 for your Oracle version and OS.
If OPatch needs upgrading:
# Step 1 — Backup existing OPatch directory
mv $ORACLE_HOME/OPatch $ORACLE_HOME/OPatch_backup_$(date +%Y%m%d)
# Step 2 — Unzip new OPatch into ORACLE_HOME
# The zip extracts as an "OPatch" folder directly
unzip -q /stage/patches/p6880880_190000_Linux-x86-64.zip -d $ORACLE_HOME
# Step 3 — Verify new version
$ORACLE_HOME/OPatch/opatch version4.3 — Identify and Download the Correct Patch from MOS
Why? Oracle releases patches quarterly. You must download the correct patch for your exact Oracle version and OS platform. Applying a patch for the wrong version or wrong OS will fail or corrupt the installation.
How to find the latest 19c RU on MOS:
- Log into MOS: https://support.oracle.com
- Click Patches & Updates tab
- In Patch Search → select Product or Family (Advanced)
- Product =
Oracle Database - Release =
19.x.x.x.x - Platform =
Linux x86-64 - Click Search
- Look for patch named
Database Release Update 19.xx.x.x.x— pick the latest
📎 MOS Doc ID 2694520.1 — Oracle Database 19c Proactive Patch — lists all current recommended patches in one place. Always start here.
# After downloading — verify the patch zip is complete
ls -lh /stage/patches/p<PATCHNUM>_190000_Linux-x86-64.zip
# Verify checksum against MOS download page
sha256sum /stage/patches/p<PATCHNUM>_190000_Linux-x86-64.zip
# Unzip the patch to staging area
mkdir -p /stage/patches/unzipped
unzip -q /stage/patches/p<PATCHNUM>_190000_Linux-x86-64.zip \
-d /stage/patches/unzipped
# List what was extracted — should see a numbered folder (the patch ID)
ls -l /stage/patches/unzipped/4.4 — Read the Patch README
Why? Every patch ships with a README file that contains patch-specific instructions, known issues, pre-requisites, and sometimes special steps that differ from the standard process. Not reading the README is the most common cause of patching mistakes.
# The README is inside the extracted patch directory
ls /stage/patches/unzipped/<PATCHNUM>/
# Read it fully before proceeding
# Key things to look for:
# - Minimum OPatch version required
# - Any pre-install steps specific to this patch
# - Any post-install steps beyond standard datapatch
# - Known issues or conflicts
less /stage/patches/unzipped/<PATCHNUM>/README.html
# OR
less /stage/patches/unzipped/<PATCHNUM>/README.txt4.5 — Check Disk Space for Patching
Why? OPatch takes a backup of all files it will replace before applying the patch. This backup goes into
$ORACLE_HOME/.patch_storage. If there is not enough space, OPatch will fail mid-patch which is a dangerous situation.
bash
# Check ORACLE_HOME filesystem — need at least 2-3 GB free
df -hP $ORACLE_HOME
# Check /tmp — OPatch uses /tmp during operations
df -hP /tmp
# Check current size of patch_storage (existing backups from previous patches)
du -sh $ORACLE_HOME/.patch_storage 2>/dev/null || echo "No previous patch storage found"⚠️ IMPORTANT: If
/oracleor/u01filesystem is above 85% used, clean up old patch backups from.patch_storageor ask your storage team to extend the filesystem BEFORE patching.
4.6 — Run OPatch Prerequisite Check (Without Applying)
Why? OPatch has a built-in prereq check that validates everything before touching a single file. It checks for conflicts with existing patches, verifies OPatch version, checks permissions, and checks disk space. This is a dry-run — it changes nothing. Always run it first.
su - oracle
cd /stage/patches/unzipped/<PATCHNUM>
# Run prereq check only — does NOT apply the patch
$ORACLE_HOME/OPatch/opatch prereq CheckConflictAgainstOHWithDetail \
-ph /stage/patches/unzipped/<PATCHNUM>What to look for in output:
OPatch succeeded. ← This is what you want to see⚠️ IMPORTANT: If prereq check shows
Patch conflict detected— stop. Do NOT proceed with patching until the conflict is resolved. Check the conflict details in the output, search MOS for the conflicting patches, and either remove the conflicting patch or get a merged patch from Oracle Support.
4.7 — Check for Running Database Sessions
Why? The database must be shut down before applying the patch. But before shutting down, check for active sessions. In production, coordinate with application teams for a maintenance window. Never shut down a database with active transactions without notice.
sqlplus / as sysdba
set linesize 180
set pagesize 100
col username for a20
col osuser for a20
col machine for a30
col program for a30
col status for a10
col logon_time for a22
-- Shows all active user sessions
SELECT username, osuser, machine, program, status, logon_time
FROM v$session
WHERE type = 'USER'
AND username IS NOT NULL
ORDER BY logon_time;
-- Quick count of active sessions
SELECT COUNT(*) active_sessions
FROM v$session
WHERE type = 'USER'
AND status = 'ACTIVE';4.8 — Take RMAN Backup Before Patching
Why? This is your safety net. If the patch goes wrong and rollback also fails (rare but it happens), the RMAN backup is your last resort to restore the database. Never patch a production database without a valid recent backup.
bash
su - oracle
# Take a full database backup before patching
rman target /
RMAN> BACKUP DATABASE PLUS ARCHIVELOG;
RMAN> LIST BACKUP SUMMARY; -- Confirm backup completed
RMAN> EXIT;⚠️ IMPORTANT: If a full RMAN backup was taken within the last 24 hours and no significant data changes have happened, you can skip this step in non-production environments. In production — always take a fresh backup.
4.9 — Record Pre-Patch Baseline
Why? You need a record of exactly what the system looked like BEFORE the patch. This is used for comparison during post-patch checks and as evidence for your change management record.
sqlplus / as sysdba
set linesize 200
set pagesize 100
col comp_name for a50
col version for a15
col status for a12
-- Record current component versions
SELECT comp_name, version, status
FROM dba_registry
ORDER BY comp_name;
-- Record current invalid object count
SELECT COUNT(*) pre_patch_invalid_count
FROM dba_objects
WHERE status = 'INVALID';# Record current patch inventory to a file for reference
$ORACLE_HOME/OPatch/opatch lsinventory > /tmp/pre_patch_inventory_$(date +%Y%m%d).txt
cat /tmp/pre_patch_inventory_$(date +%Y%m%d).txt5. Patching Activity
⚠️ IMPORTANT: From this point onwards the database will be shut down. Ensure your maintenance window is active, application teams are notified, and monitoring alerts are suppressed (blackout in OEM if configured).
5.1 — Stop All Database Services and Shut Down Database
Why? Oracle binaries cannot be patched while they are in use. The database, listener, and any other Oracle processes using this ORACLE_HOME must be stopped before OPatch can replace the binary files.
su - oracle
# Step 1 — Shut down the listener first
lsnrctl stop
# Confirm listener is down
lsnrctl status # Should show "TNS-12541: No listener"
# Step 2 — Shut down the database
sqlplus / as sysdba-- Graceful shutdown — waits for all active transactions to complete
-- Use IMMEDIATE if NORMAL takes too long (more than 5 minutes)
SHUTDOWN IMMEDIATE;
EXIT;# Step 3 — Confirm no Oracle processes are running from this ORACLE_HOME
ps -ef | grep ora_ | grep -v grep
ps -ef | grep $ORACLE_HOME | grep -v grep
# Expected: No output (or only grep itself)⚠️ IMPORTANT: If any Oracle process is still running after
SHUTDOWN IMMEDIATE, do NOT proceed. Identify the process and stop it cleanly. Patching while Oracle processes are running will corrupt the Oracle Home.
5.2 — Set ORACLE_HOME Environment (Confirm Before Patching)
Why? OPatch uses the ORACLE_HOME environment variable to know which Oracle Home to patch. If this is set incorrectly, you could accidentally patch the wrong Oracle Home. Always verify before running OPatch.
su - oracle
# Confirm environment is pointing to correct ORACLE_HOME
echo "ORACLE_HOME = $ORACLE_HOME"
echo "ORACLE_BASE = $ORACLE_BASE"
echo "ORACLE_SID = $ORACLE_SID"
# Also confirm OPatch is using the correct home
$ORACLE_HOME/OPatch/opatch lsinventory | grep "Oracle Home"5.3 — Apply the Patch Using OPatch
Why
opatch apply? This is the command that actually replaces the old Oracle binary files and libraries with the new patched versions. OPatch first backs up all files it will replace (into.patch_storage), then replaces them. If something fails, OPatch uses this backup to roll back.
su - oracle
# Navigate to the extracted patch directory
cd /stage/patches/unzipped/<PATCHNUM>
# Apply the patch
# -silent = no interactive prompts
# -oh = explicitly specify ORACLE_HOME (best practice to avoid ambiguity)
$ORACLE_HOME/OPatch/opatch apply -silent \
-oh $ORACLE_HOME
# Watch for progress — OPatch shows files being patchedExpected output at the end:
Patching component oracle.rdbms, 19.x.x.x.x...
Patch <PATCHNUM> successfully applied.
OPatch succeeded.⚠️ IMPORTANT: If OPatch shows any error during apply — do NOT start the database. First run the rollback (Section 7) to restore to pre-patch state, then investigate the error. Starting a database with a partially applied patch can cause data dictionary corruption.
5.4 — Verify Patch Was Applied Successfully
Why? Confirm the patch is now listed in the Oracle inventory before starting the database. This is your confirmation that OPatch completed successfully.
su - oracle
# Check patch is now listed in inventory
$ORACLE_HOME/OPatch/opatch lsinventory | grep -E "Patch|PATCHNUM"
# Detailed check
$ORACLE_HOME/OPatch/opatch lsinventory -detail | grep -A5 "<PATCHNUM>"5.5 — Start the Database and Listener
Why start before datapatch? The database must be open (not just mounted) for datapatch to run. datapatch applies SQL changes to the data dictionary, which requires the database to be in READ WRITE mode.
su - oracle
# Start the database
sqlplus / as sysdbaSTARTUP;
-- Confirm database is open
SELECT name, open_mode FROM v$database;
EXIT;# Start the listener
lsnrctl start
# Confirm listener is up and database is registered
lsnrctl status5.6 — Run datapatch (CRITICAL STEP)
Why datapatch? OPatch patches the Oracle software binaries (the files on disk). But Oracle also stores version-specific SQL objects, packages, and dictionary tables inside the database itself. datapatch updates these internal database objects to match the newly patched binaries. Without datapatch, there will be a mismatch between the binary version and the dictionary version — this causes ORA- errors and incorrect behavior.
⚠️ IMPORTANT: datapatch MUST be run after every OPatch apply. It is not optional. Skipping datapatch is one of the most common patching mistakes.
su - oracle
# Navigate to OPatch utilities directory
cd $ORACLE_HOME/OPatch
# Run datapatch
# -verbose = shows detailed progress of each SQL script being applied
./datapatch -verboseWhat to look for in datapatch output:
SQL Patching tool version 19.x.x.x.x
Copyright (c) 2012, 2023, Oracle. All rights reserved.
Log file for this invocation: /u01/app/oracle/cfgtoollogs/sqlpatch/<date>/
Connecting to database...OK
Bootstrapping registry and package to current versions...done
Determining current state...done
Adding patches to installation queue and performing prereq checks...done
Installation queue:
For the following patches, no SQL actions will be performed:
None
The following patches will be applied:
<PATCHNUM> (DATABASE RELEASE UPDATE 19.xx.x.x.x)
Installing patches...
Patch installation complete. Total patches installed: 1
Validating logfiles...done
Patch <PATCHNUM> apply: SUCCESS
logfile: /u01/app/oracle/cfgtoollogs/sqlpatch/.../...log (no errors)
datapatch: ALL PATCHES APPLIED SUCCESSFULLY.⚠️ IMPORTANT: If datapatch shows any failures, check the log file path shown in the output. Common issues: database not fully open, temporary tablespace full, INVALID objects blocking compilation.
# Check datapatch log for errors if needed
ls -lrt /u01/app/oracle/cfgtoollogs/sqlpatch/
# Convention B:
ls -lrt /oracle/cfgtoollogs/sqlpatch/6. Post-Patching Checks
⚠️ IMPORTANT: Post-patch checks are mandatory. Do not close your maintenance window or inform the team that patching is complete until every check below passes.
6.1 — Confirm New Patch Version
Why? First confirmation that the patch is correctly reflected in both the Oracle binary and the data dictionary.
sqlplus / as sysdba
set linesize 150
set pagesize 50
col banner for a80
-- Confirms binary version matches expected patched version
SELECT banner FROM v$version WHERE banner LIKE 'Oracle%';
-- Shows full version including patch level
SELECT version, version_full FROM v$instance;# Confirms patch is listed in OPatch inventory
$ORACLE_HOME/OPatch/opatch lsinventory | grep -E "Patch|Oracle Database"6.2 — Verify datapatch Applied Successfully in the Database
Why? Even if datapatch appeared to succeed on the command line, verify it inside the database.
dba_registry_sqlpatchis the authoritative record of what datapatch has applied.
set linesize 200
set pagesize 100
col patch_id for 9999999999
col patch_uid for 9999999999
col version for a15
col status for a15
col description for a55
col action_time for a25
-- Shows all patches applied by datapatch and their status
SELECT patch_id, patch_uid, version, status, description, action_time
FROM dba_registry_sqlpatch
ORDER BY action_time DESC;What to look for: Your patch number must appear with SUCCESS in the status column.
6.3 — Check Database is Open and Healthy
set linesize 150
set pagesize 50
col name for a12
col db_unique_name for a20
col open_mode for a15
col log_mode for a15
col instance_name for a15
col status for a12
col host_name for a30
SELECT name, db_unique_name, open_mode, log_mode
FROM v$database;
SELECT instance_name, version_full, host_name, status
FROM v$instance;6.4 — Check All Datafiles Are Online
set linesize 200
set pagesize 100
col file# for 999
col tablespace_name for a25
col status for a12
col name for a70
SELECT file#, tablespace_name, status, name
FROM v$datafile
ORDER BY file#;What to look for: All files must show ONLINE.
6.5 — Check for INVALID Objects After Patching
Why? Patching sometimes invalidates PL/SQL objects that reference changed packages or types. datapatch recompiles most of them automatically, but some may remain invalid. These must be recompiled before application teams reconnect.
set linesize 180
set pagesize 100
col owner for a20
col object_name for a45
col object_type for a25
col status for a10
-- Check for any invalid objects
SELECT owner, object_name, object_type, status
FROM dba_objects
WHERE status = 'INVALID'
ORDER BY owner, object_type, object_name;
-- Count
SELECT COUNT(*) post_patch_invalid_count
FROM dba_objects
WHERE status = 'INVALID';⚠️ IMPORTANT: If invalid count is higher than your pre-patch baseline recorded in Section 4.9, run
utlrp.sqlto recompile:
-- Recompile all invalid objects
@?/rdbms/admin/utlrp.sql
-- Re-verify
SELECT COUNT(*) FROM dba_objects WHERE status = 'INVALID';6.6 — Verify All Components Are VALID
set linesize 200
set pagesize 100
col comp_name for a50
col version for a15
col status for a12
SELECT comp_name, version, status
FROM dba_registry
ORDER BY comp_name;What to look for: Every component must show VALID. Compare versions against pre-patch baseline — they should now show the new patched version numbers.
6.7 — Check Alert Log for Post-Patch Errors
# Scan alert log for any errors since patching started
tail -300 /u01/app/oracle/diag/rdbms/orcl/ORCL/trace/alert_ORCL.log \
| grep -E "ORA-|Error|WARNING|CORRUPTED|FAILED"
# Convention B:
tail -300 /oracle/diag/rdbms/orcl/ORCL/trace/alert_ORCL.log \
| grep -E "ORA-|Error|WARNING|CORRUPTED|FAILED"6.8 — Verify Listener is Running and Database is Registered
# Confirm listener is up
lsnrctl status
# Test actual TNS connection end-to-end
sqlplus system/Oracle_123@localhost:1521/ORCL6.9 — Record Post-Patch Inventory
Why? Save the post-patch OPatch inventory to a file. This is your evidence for change management, audit, and future reference when someone asks “what patch level is this database on?”
# Save post-patch inventory to file
$ORACLE_HOME/OPatch/opatch lsinventory > /tmp/post_patch_inventory_$(date +%Y%m%d).txt
# View it
cat /tmp/post_patch_inventory_$(date +%Y%m%d).txt
# Compare with pre-patch baseline
diff /tmp/pre_patch_inventory_$(date +%Y%m%d).txt \
/tmp/post_patch_inventory_$(date +%Y%m%d).txt7. Patch Rollback Procedure
When to use this? If the patch causes unexpected issues and you need to return to the pre-patch state. OPatch rollback reverses the binary changes. datapatch rollback reverses the dictionary changes.
⚠️ IMPORTANT: Rollback must be done in reverse order — datapatch rollback first (while DB is open), then OPatch rollback (while DB is down).
7.1 — Run datapatch Rollback (Database Must Be Open)
su - oracle
# Rollback the patch at SQL/dictionary level first
cd $ORACLE_HOME/OPatch
./datapatch -verbose -rollback <PATCHNUM>7.2 — Shut Down Database and Listener
su - oracle
sqlplus / as sysdbaSHUTDOWN IMMEDIATE;
EXIT;lsnrctl stop7.3 — Rollback Patch Using OPatch
su - oracle
# Roll back the patch binary changes
$ORACLE_HOME/OPatch/opatch rollback -id <PATCHNUM> -silent \
-oh $ORACLE_HOMEExpected output:
OPatch succeeded.7.4 — Start Database and Verify Rollback
su - oracle
sqlplus / as sysdbaSTARTUP;
SELECT banner FROM v$version;
-- Confirm patch is no longer in registry
SELECT patch_id, status FROM dba_registry_sqlpatch ORDER BY action_time DESC;
EXIT;# Confirm patch is no longer in OPatch inventory
$ORACLE_HOME/OPatch/opatch lsinventory | grep <PATCHNUM>
# Should return no output (patch is gone)8. Quick Reference Card
| Task | Command |
|---|---|
| Check current version | SELECT version_full FROM v$instance; |
| Check installed patches | opatch lsinventory |
| Check OPatch version | opatch version |
| Backup OPatch | mv $ORACLE_HOME/OPatch $ORACLE_HOME/OPatch_backup_$(date +%Y%m%d) |
| Upgrade OPatch | unzip p6880880_*.zip -d $ORACLE_HOME |
| Run prereq check | opatch prereq CheckConflictAgainstOHWithDetail -ph <PATCHDIR> |
| Shut down database | SHUTDOWN IMMEDIATE; |
| Stop listener | lsnrctl stop |
| Apply patch | opatch apply -silent -oh $ORACLE_HOME |
| Start database | STARTUP; |
| Start listener | lsnrctl start |
| Run datapatch | ./datapatch -verbose |
| Check datapatch result | SELECT patch_id,status FROM dba_registry_sqlpatch; |
| Check invalid objects | SELECT count(*) FROM dba_objects WHERE status='INVALID'; |
| Recompile invalids | @?/rdbms/admin/utlrp.sql |
| Check components | SELECT comp_name,status FROM dba_registry; |
| Save patch inventory | opatch lsinventory > /tmp/post_patch_$(date +%Y%m%d).txt |
| Rollback datapatch | ./datapatch -verbose -rollback <PATCHNUM> |
| Rollback OPatch | opatch rollback -id <PATCHNUM> -silent |
| MOS Patch Advisory | Doc ID 2694520.1 |
| MOS OPatch Download | Doc ID 6880880.1 |
This SOP covers everything you need to patch Oracle Database 19c on a standalone Linux server without referring to any other source. Always read the patch README, never skip datapatch, and record your pre and post patch inventory for every patching activity.
