Oracle 19c Patching on Linux – Complete Step-by-Step Guide

Share:
Article Summary

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

ItemDetail
Oracle Version19c (19.3 base + applicable RU)
OSOracle Linux 7.x / RHEL 7.x or 8.x
Patch TypeRelease Update (RU) — Standalone (Non-RAC)
Patching MethodIn-place (same ORACLE_HOME)
MOS ReferenceDoc ID 2694520.1 (19c Patch Advisories)
MOS ReferenceDoc 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.

ItemConvention AConvention 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.

TermWhat 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 PatchA single bug fix patch for a specific issue. Applied on top of RU when a specific bug needs fixing urgently.
OPatchOracle’s patching utility. All patches are applied and rolled back using OPatch. Lives inside ORACLE_HOME/OPatch.
datapatchA 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 ConflictWhen two patches modify the same file. OPatch detects this automatically during prereq check. Must be resolved before applying.
Rolling PatchPatching one node at a time in RAC — database stays online. Not applicable for standalone.
In-place PatchingApplying the patch directly to the existing ORACLE_HOME. Database must be down.
Out-of-place PatchingInstalling 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 version

4.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:

  1. Log into MOS: https://support.oracle.com
  2. Click Patches & Updates tab
  3. In Patch Search → select Product or Family (Advanced)
  4. Product = Oracle Database
  5. Release = 19.x.x.x.x
  6. Platform = Linux x86-64
  7. Click Search
  8. 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.txt

4.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 /oracle or /u01 filesystem is above 85% used, clean up old patch backups from .patch_storage or 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).txt

5. 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 patched

Expected 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 sysdba
STARTUP;

-- 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 status

5.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 -verbose

What 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_sqlpatch is 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.sql to 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/ORCL

6.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).txt

7. 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 sysdba
SHUTDOWN IMMEDIATE;
EXIT;
lsnrctl stop

7.3 — Rollback Patch Using OPatch

su - oracle

# Roll back the patch binary changes
$ORACLE_HOME/OPatch/opatch rollback -id <PATCHNUM> -silent \
    -oh $ORACLE_HOME

Expected output:

OPatch succeeded.

7.4 — Start Database and Verify Rollback

su - oracle
sqlplus / as sysdba
STARTUP;
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

TaskCommand
Check current versionSELECT version_full FROM v$instance;
Check installed patchesopatch lsinventory
Check OPatch versionopatch version
Backup OPatchmv $ORACLE_HOME/OPatch $ORACLE_HOME/OPatch_backup_$(date +%Y%m%d)
Upgrade OPatchunzip p6880880_*.zip -d $ORACLE_HOME
Run prereq checkopatch prereq CheckConflictAgainstOHWithDetail -ph <PATCHDIR>
Shut down databaseSHUTDOWN IMMEDIATE;
Stop listenerlsnrctl stop
Apply patchopatch apply -silent -oh $ORACLE_HOME
Start databaseSTARTUP;
Start listenerlsnrctl start
Run datapatch./datapatch -verbose
Check datapatch resultSELECT patch_id,status FROM dba_registry_sqlpatch;
Check invalid objectsSELECT count(*) FROM dba_objects WHERE status='INVALID';
Recompile invalids@?/rdbms/admin/utlrp.sql
Check componentsSELECT comp_name,status FROM dba_registry;
Save patch inventoryopatch lsinventory > /tmp/post_patch_$(date +%Y%m%d).txt
Rollback datapatch./datapatch -verbose -rollback <PATCHNUM>
Rollback OPatchopatch rollback -id <PATCHNUM> -silent
MOS Patch AdvisoryDoc ID 2694520.1
MOS OPatch DownloadDoc 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.

Was this helpful?

Written by

W3buddy
W3buddy

Explore W3Buddy for in-depth guides, breaking tech news, and expert analysis on AI, cybersecurity, databases, web development, and emerging technologies.