{"id":5767,"date":"2026-07-16T04:36:46","date_gmt":"2026-07-15T23:06:46","guid":{"rendered":"https:\/\/w3buddy.com\/?p=5767"},"modified":"2026-07-19T22:14:26","modified_gmt":"2026-07-19T16:44:26","slug":"oracle-dataguard-19c-patching","status":"publish","type":"post","link":"https:\/\/w3buddy.com\/blog\/oracle-dataguard-19c-patching\/","title":{"rendered":"Oracle Data Guard 19c Patching"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">A complete production-ready SOP for patching Oracle Data Guard 19c on Linux. Covers the rolling patch method using the standby-first approach, Grid Infrastructure patching in DG environments, datapatch execution, switchover after patching, and full post-patch validation on both primary and standby \u2014 with real commands, expected outputs, and consultant-level notes for both standard OFA and enterprise custom path conventions.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">1. Document Info<\/h3>\n\n\n\n<figure class=\"wp-block-table has-small-font-size\"><table><thead><tr><th>Item<\/th><th>Detail<\/th><\/tr><\/thead><tbody><tr><td>Oracle Version<\/td><td>19c (19.3+)<\/td><\/tr><tr><td>OS<\/td><td>Oracle Linux 7.x \/ RHEL 7.x or 8.x<\/td><\/tr><tr><td>Patch Type<\/td><td>Release Update (RU) \u2014 Data Guard Environment<\/td><\/tr><tr><td>Primary DB<\/td><td>ORCL (dbserver01)<\/td><\/tr><tr><td>Standby DB<\/td><td>ORCL_STBY (dbserver02)<\/td><\/tr><tr><td>Patching Method<\/td><td>Standby-First Rolling (zero downtime on primary)<\/td><\/tr><tr><td>MOS Reference<\/td><td>Doc ID 2694520.1 (19c Patch Advisories)<\/td><\/tr><tr><td>MOS Reference<\/td><td>Doc ID 1265700.1 (Patching with Data Guard)<\/td><\/tr><tr><td>MOS Reference<\/td><td>Doc ID 1599845.1 (DG Patching Best Practices)<\/td><\/tr><tr><td>MOS Reference<\/td><td>Doc ID 1410202.1 (OPatch Quick Start)<\/td><\/tr><tr><td>Prepared By<\/td><td>Oracle DBA \/ Consultant<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">2. Data Guard Patching \u2014 Concepts You Must Know First<\/h3>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd <strong>Why is DG patching different from standalone?<\/strong> In standalone patching you have one database, one Oracle Home, and patching requires full downtime. In a Data Guard environment you have two databases (primary and standby) each with their own Oracle Home. The power of Data Guard patching is that you can patch the standby first while the primary stays fully online, then do a planned switchover so the newly patched standby becomes the primary \u2014 resulting in near-zero downtime for the application.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">Key DG Patching Concepts<\/h4>\n\n\n\n<figure class=\"wp-block-table has-small-font-size\"><table><thead><tr><th>Concept<\/th><th>What It Means<\/th><\/tr><\/thead><tbody><tr><td>Standby-First Patching<\/td><td>Patch the standby Oracle Home first while primary is running. Then switchover. Then patch old primary (now standby). This is the gold standard approach \u2014 minimum application downtime.<\/td><\/tr><tr><td>Transient Logical Standby<\/td><td>An advanced method for zero-downtime DB upgrades. Not covered in this SOP \u2014 covered in the Database Upgrade SOP.<\/td><\/tr><tr><td>Mixed Patch Level<\/td><td>During standby-first patching, primary and standby temporarily run on different patch levels. This is normal and supported by Oracle for the duration of the patching window.<\/td><\/tr><tr><td>Convention B Advantage<\/td><td>When standby uses a separate ORACLE_HOME directory (<code>19.31Standby<\/code> vs <code>19.31<\/code>), you can pre-stage the patch in the standby home without affecting the primary home at all. This is a key advantage of the separate home approach.<\/td><\/tr><tr><td>DG Broker During Patching<\/td><td>Keep Broker running during patching \u2014 it monitors the configuration health. Use Broker for the switchover step after standby is patched.<\/td><\/tr><tr><td>datapatch in DG<\/td><td>datapatch is run only ONCE \u2014 on whichever database is the PRIMARY at the time. It applies SQL changes to the data dictionary which is then replicated to the standby via redo.<\/td><\/tr><tr><td>MRP During Patching<\/td><td>Managed Recovery Process (MRP) on standby must be stopped before patching the standby Oracle Home. Restart it after patching completes.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">DG Patching Sequence Overview<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>High Level Steps \u2014 Standby-First Rolling Approach:\n\nPHASE 1 \u2014 Patch Standby (Primary stays online \u2014 zero application downtime)\n  Step 1  \u2192 Pre-patch checks on both servers\n  Step 2  \u2192 Stop MRP on standby\n  Step 3  \u2192 Patch Oracle Home on standby server\n  Step 4  \u2192 Start MRP on standby \u2014 let it catch up\n  Step 5  \u2192 Verify standby is healthy and in sync\n\nPHASE 2 \u2014 Switchover (Brief application reconnect \u2014 seconds to minutes)\n  Step 6  \u2192 Validate DG and standby is ready for switchover\n  Step 7  \u2192 Perform switchover (standby becomes new primary)\n  Step 8  \u2192 Run datapatch on new primary (was standby)\n  Step 9  \u2192 Verify new primary is healthy\n\nPHASE 3 \u2014 Patch Old Primary (Now Standby \u2014 no application impact)\n  Step 10 \u2192 Patch Oracle Home on old primary (now standby)\n  Step 11 \u2192 Start MRP on old primary standby\n  Step 12 \u2192 Verify full DG configuration is healthy\n  Step 13 \u2192 Optional switchover back to original primary<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd <strong>Total application downtime<\/strong> with this approach is only the switchover time \u2014 typically 30 seconds to 5 minutes depending on active sessions and redo volume in transit.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">Convention B \u2014 Key Advantage During DG Patching<\/h4>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd <strong>Why Convention B is better for patching?<\/strong> In Convention B, primary uses <code>\/oracle\/RDBMS\/19.31<\/code> and standby uses <code>\/oracle\/RDBMS\/19.31Standby<\/code>. These are completely separate directories. You can:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Pre-patch the standby home (<code>19.31Standby<\/code>) at any time without touching the primary home (<code>19.31<\/code>)<\/li>\n\n\n\n<li>After switchover, patch the old primary home (<code>19.31<\/code>) while it runs as standby<\/li>\n\n\n\n<li>Both homes can have different patch levels simultaneously without any conflict<\/li>\n\n\n\n<li>Rollback is as simple as pointing back to the old home<\/li>\n<\/ul>\n<\/blockquote>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd In Convention A (same home name on both servers), the homes are still separate (on different servers) \u2014 patching is still independent. The difference is mostly organizational clarity.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">3. Path Conventions<\/h3>\n\n\n\n<figure class=\"wp-block-table has-small-font-size\"><table><thead><tr><th>Item<\/th><th>Convention A Primary<\/th><th>Convention A Standby<\/th><\/tr><\/thead><tbody><tr><td>Oracle Home<\/td><td>\/u01\/app\/oracle\/product\/19.3.0\/dbhome_1<\/td><td>\/u01\/app\/oracle\/product\/19.3.0\/dbhome_1<\/td><\/tr><tr><td>Oracle Base<\/td><td>\/u01\/app\/oracle<\/td><td>\/u01\/app\/oracle<\/td><\/tr><tr><td>oraInventory<\/td><td>\/u01\/app\/oraInventory<\/td><td>\/u01\/app\/oraInventory<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<figure class=\"wp-block-table has-small-font-size\"><table><thead><tr><th>Item<\/th><th>Convention B Primary<\/th><th>Convention B Standby<\/th><\/tr><\/thead><tbody><tr><td>Oracle Home<\/td><td>\/oracle\/RDBMS\/19.31<\/td><td>\/oracle\/RDBMS\/19.31Standby<\/td><\/tr><tr><td>Oracle Base<\/td><td>\/oracle<\/td><td>\/oracle<\/td><\/tr><tr><td>oraInventory<\/td><td>\/oracle\/oraInventory<\/td><td>\/oracle\/oraInventory<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd All examples use Convention A. For Convention B substitute the respective paths. The steps are identical \u2014 only directory paths differ.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">4. Pre-Patching Checks \u2014 Both Servers<\/h3>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u26a0\ufe0f <strong>IMPORTANT:<\/strong> Every pre-check must be completed on BOTH primary and standby before starting. Patching a Data Guard configuration that is not fully healthy is one of the most common causes of patching failures and extended outages.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">4.1 \u2014 Confirm Current Patch Level on Both Servers<\/h4>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd <strong>Why?<\/strong> You must document exactly what patch level both primary and standby are on before starting. Both should be on the same patch level before you begin. If they are already on different patch levels \u2014 fix that first.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code># On PRIMARY \u2014 check Oracle Home patch inventory\nsu - oracle\n$ORACLE_HOME\/OPatch\/opatch lsinventory\n\n# Quick summary\n$ORACLE_HOME\/OPatch\/opatch lsinventory | grep -E \"Oracle Database|Patch \"<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code># On STANDBY \u2014 check Oracle Home patch inventory\nsu - oracle\n$ORACLE_HOME\/OPatch\/opatch lsinventory | grep -E \"Oracle Database|Patch \"<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On PRIMARY \u2014 confirm DB version and patch level\nsqlplus \/ as sysdba\n\nset linesize 150\nset pagesize 50\ncol banner for a80\n\nSELECT banner FROM v$version WHERE banner LIKE 'Oracle%';\n\nSELECT version, version_full FROM v$instance;<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">4.2 \u2014 Verify Data Guard Configuration is Fully Healthy<\/h4>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd <strong>Why?<\/strong> Data Guard must be completely healthy before patching. Any existing errors, apply lag, or archive gaps will be amplified during patching. Fix all DG issues before touching any patch.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>-- Connect to Broker from PRIMARY\ndgmgrl sys\/Oracle_123@ORCL\n\n-- Overall configuration health\nDGMGRL&gt; SHOW CONFIGURATION;\n-- Must show: SUCCESS\n\n-- Primary database details\nDGMGRL&gt; SHOW DATABASE VERBOSE 'ORCL';\n\n-- Standby database details\nDGMGRL&gt; SHOW DATABASE VERBOSE 'ORCL_STBY';\n\n-- Validate standby is ready\nDGMGRL&gt; VALIDATE DATABASE 'ORCL_STBY';\n\n-- Check lag\nDGMGRL&gt; SHOW DATABASE 'ORCL_STBY' 'ApplyLagSecs';\nDGMGRL&gt; SHOW DATABASE 'ORCL_STBY' 'TransportLagSecs';\n\nDGMGRL&gt; EXIT;<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u26a0\ufe0f <strong>IMPORTANT:<\/strong> If Broker shows WARNING or ERROR \u2014 stop. Resolve the DG issue first. Common issues to resolve before patching:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Archive destination error on primary<\/li>\n\n\n\n<li>MRP not running on standby<\/li>\n\n\n\n<li>Archive log gap on standby<\/li>\n\n\n\n<li>Transport lag above acceptable threshold<\/li>\n<\/ul>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>-- Additional DG health checks directly on each DB\n-- On PRIMARY\nsqlplus \/ as sysdba\n\nset linesize 200\nset pagesize 50\ncol dest_id   for 999\ncol dest_name for a20\ncol status    for a12\ncol error     for a45\n\n-- Check archive destinations \u2014 DEST_ID 2 must be VALID with no error\nSELECT dest_id, dest_name, status, error\nFROM   v$archive_dest\nWHERE  dest_id IN (1,2)\nORDER BY dest_id;<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On STANDBY \u2014 check MRP and apply lag\nsqlplus \/ as sysdba\n\nset linesize 200\nset pagesize 50\ncol process   for a12\ncol status    for a20\ncol sequence# for 999999\n\n-- MRP must be running\nSELECT process, status, sequence#\nFROM   v$managed_standby\nWHERE  process = 'MRP0';\n\n-- Apply lag must be minimal\nset linesize 200\ncol name  for a30\ncol value for a40\ncol unit  for a20\n\nSELECT name, value, unit\nFROM   v$dataguard_stats\nWHERE  name IN ('transport lag','apply lag')\nORDER BY name;<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">4.3 \u2014 Check for Archive Log Gaps on Standby<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On STANDBY\nset linesize 150\nset pagesize 50\ncol low_sequence#  for 999999\ncol high_sequence# for 999999\n\n-- No rows = no gaps (good to proceed)\n-- Any rows = gaps exist \u2014 resolve before patching\nSELECT thread#, low_sequence#, high_sequence#\nFROM   v$archive_gap;<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u26a0\ufe0f <strong>IMPORTANT:<\/strong> If archive gaps exist, the standby will not be current. After patching and switchover, the new primary (was standby) may be missing transactions. Resolve all gaps before starting the patching process.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">4.4 \u2014 Verify OPatch Version on Both Servers and Upgrade if Needed<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># On PRIMARY\nsu - oracle\n$ORACLE_HOME\/OPatch\/opatch version\n\n# On STANDBY\nsu - oracle\n$ORACLE_HOME\/OPatch\/opatch version<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd Compare both versions against the minimum required OPatch version in the patch README.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Upgrade OPatch on standby if needed (do standby first):<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># On STANDBY as oracle user\nsu - oracle\n\n# Backup existing OPatch\nmv $ORACLE_HOME\/OPatch \\\n   $ORACLE_HOME\/OPatch_backup_$(date +%Y%m%d)\n\n# Unzip new OPatch into Oracle Home\nunzip -q \/stage\/patches\/p6880880_190000_Linux-x86-64.zip \\\n      -d $ORACLE_HOME\n\n# Verify new version\n$ORACLE_HOME\/OPatch\/opatch version<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code># On PRIMARY as oracle user \u2014 upgrade OPatch here too\nsu - oracle\nmv $ORACLE_HOME\/OPatch \\\n   $ORACLE_HOME\/OPatch_backup_$(date +%Y%m%d)\nunzip -q \/stage\/patches\/p6880880_190000_Linux-x86-64.zip \\\n      -d $ORACLE_HOME\n$ORACLE_HOME\/OPatch\/opatch version<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcce Download latest OPatch: MOS Doc ID <strong>6880880.1<\/strong><\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">4.5 \u2014 Download Patch and Stage on Both Servers<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># Download patch on PRIMARY\nls -lh \/stage\/patches\/p&lt;PATCHNUM&gt;_190000_Linux-x86-64.zip\n\n# Verify checksum\nsha256sum \/stage\/patches\/p&lt;PATCHNUM&gt;_190000_Linux-x86-64.zip\n\n# Copy patch to STANDBY\nscp \/stage\/patches\/p&lt;PATCHNUM&gt;_190000_Linux-x86-64.zip \\\n    oracle@dbserver02:\/stage\/patches\/\n\n# Verify on STANDBY\nssh oracle@dbserver02 \\\n    \"ls -lh \/stage\/patches\/p&lt;PATCHNUM&gt;_190000_Linux-x86-64.zip\"\n\n# Unzip on STANDBY first (we patch standby first)\nssh oracle@dbserver02 \\\n    \"mkdir -p \/stage\/patches\/unzipped &amp;&amp; \\\n     unzip -q \/stage\/patches\/p&lt;PATCHNUM&gt;_190000_Linux-x86-64.zip \\\n     -d \/stage\/patches\/unzipped\"\n\n# Unzip on PRIMARY (for later)\nmkdir -p \/stage\/patches\/unzipped\nunzip -q \/stage\/patches\/p&lt;PATCHNUM&gt;_190000_Linux-x86-64.zip \\\n      -d \/stage\/patches\/unzipped\n\n# Verify on both\nls -l \/stage\/patches\/unzipped\/\nssh oracle@dbserver02 \"ls -l \/stage\/patches\/unzipped\/\"<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">4.6 \u2014 Read Patch README<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># Read the README on STANDBY\nless \/stage\/patches\/unzipped\/&lt;PATCHNUM&gt;\/README.html<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd <strong>What to look for:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Does this patch support Data Guard rolling patching? Look for <code>\"Data Guard Standby-First Patching\"<\/code> section<\/li>\n\n\n\n<li>Minimum OPatch version required<\/li>\n\n\n\n<li>Any pre-patch steps specific to this patch<\/li>\n\n\n\n<li>Any post-patch steps beyond standard datapatch<\/li>\n\n\n\n<li>Any known issues in Data Guard environments<\/li>\n<\/ul>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">4.7 \u2014 Run OPatch Conflict Check on Both Servers<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># On STANDBY \u2014 conflict check first (we patch standby first)\nsu - oracle\n$ORACLE_HOME\/OPatch\/opatch prereq \\\n    CheckConflictAgainstOHWithDetail \\\n    -ph \/stage\/patches\/unzipped\/&lt;PATCHNUM&gt;<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code># On PRIMARY \u2014 conflict check\nsu - oracle\n$ORACLE_HOME\/OPatch\/opatch prereq \\\n    CheckConflictAgainstOHWithDetail \\\n    -ph \/stage\/patches\/unzipped\/&lt;PATCHNUM&gt;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Both must show <code>OPatch succeeded.<\/code><\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">4.8 \u2014 Check Disk Space on Both Servers<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># On PRIMARY\ndf -hP $ORACLE_HOME\ndf -hP \/tmp\n\n# On STANDBY\nssh oracle@dbserver02 \"df -hP $ORACLE_HOME; df -hP \/tmp\"<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd Both servers need minimum 2-3 GB free in the Oracle Home filesystem for OPatch to store backup of replaced files.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">4.9 \u2014 Take RMAN Backup on Primary Before Patching<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>su - oracle\nrman target \/\n\nRMAN&gt; BACKUP DATABASE PLUS ARCHIVELOG;\nRMAN&gt; LIST BACKUP SUMMARY;\nRMAN&gt; EXIT;<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">4.10 \u2014 Record Pre-Patch Baseline on Both Servers<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On PRIMARY\nsqlplus \/ as sysdba\n\nset linesize 200\nset pagesize 100\ncol comp_name for a50\ncol version   for a15\ncol status    for a12\n\nSELECT comp_name, version, status\nFROM   dba_registry\nORDER BY comp_name;\n\nSELECT COUNT(*) pre_patch_invalid_count\nFROM   dba_objects\nWHERE  status = 'INVALID';\n\n-- Record datapatch history\nset linesize 200\nset pagesize 100\ncol patch_id    for 9999999999\ncol version     for a15\ncol status      for a15\ncol description for a55\ncol action_time for a25\n\nSELECT patch_id, version, status, description, action_time\nFROM   dba_registry_sqlpatch\nORDER BY action_time DESC;<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code># Save OPatch inventory from BOTH servers\nsu - oracle\n\n# Primary inventory\n$ORACLE_HOME\/OPatch\/opatch lsinventory \\\n    &gt; \/tmp\/pre_patch_PRIMARY_$(date +%Y%m%d).txt\n\n# Standby inventory\nssh oracle@dbserver02 \\\n    \"$ORACLE_HOME\/OPatch\/opatch lsinventory\" \\\n    &gt; \/tmp\/pre_patch_STANDBY_$(date +%Y%m%d).txt\n\ncat \/tmp\/pre_patch_PRIMARY_$(date +%Y%m%d).txt\ncat \/tmp\/pre_patch_STANDBY_$(date +%Y%m%d).txt<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">5. Phase 1 \u2014 Patch Standby Oracle Home<\/h3>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd <strong>What happens in Phase 1?<\/strong> The standby Oracle Home is patched while the primary database continues running and serving application traffic. During this phase the standby goes through a brief period where MRP is stopped \u2014 archivelogs from primary continue to accumulate on the standby but are not applied. After patching the standby home, MRP is restarted and the standby catches up.<\/p>\n<\/blockquote>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u26a0\ufe0f <strong>IMPORTANT:<\/strong> All steps in Phase 1 are performed on the STANDBY server unless stated otherwise. The primary database is NOT touched during Phase 1.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">5.1 \u2014 Stop MRP on Standby<\/h4>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd <strong>Why?<\/strong> MRP (Managed Recovery Process) reads from the Oracle Home binaries to apply redo. If we replace those binaries while MRP is running, MRP may crash or produce errors. Always stop MRP before patching the standby Oracle Home.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On STANDBY as oracle user\nsqlplus \/ as sysdba\n\n-- Check MRP is currently running\nset linesize 180\nset pagesize 50\ncol process  for a12\ncol status   for a20\ncol sequence# for 999999\n\nSELECT process, status, sequence#\nFROM   v$managed_standby\nWHERE  process = 'MRP0';\n\n-- Stop MRP gracefully\nALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;\n\n-- Confirm MRP has stopped \u2014 should return no rows\nSELECT process, status, sequence#\nFROM   v$managed_standby\nWHERE  process = 'MRP0';<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>What to look for after cancel:<\/strong> No <code>MRP0<\/code> row returned = MRP is stopped.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd <strong>Note:<\/strong> While MRP is stopped, the primary continues shipping archivelogs to the standby. They accumulate in the standby&#8217;s archive destination but are not applied. This is fine \u2014 they will all be applied when MRP is restarted after patching.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">5.2 \u2014 Verify Standby Database is in MOUNT State or Open Read-Only<\/h4>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd <strong>Why?<\/strong> We do not need to shut down the standby database completely to patch the Oracle Home. The standby instance can remain running in MOUNT state while we patch. This saves significant time compared to a full shutdown and startup cycle.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On STANDBY\nset linesize 150\nset pagesize 50\ncol name           for a12\ncol db_unique_name for a15\ncol open_mode      for a15\ncol database_role  for a20\n\nSELECT name, db_unique_name, open_mode, database_role\nFROM   v$database;<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd Standby can be in <code>MOUNTED<\/code> or <code>READ ONLY WITH APPLY<\/code> (Active Data Guard) state during patching. Either is fine \u2014 MRP is already stopped so no apply is happening.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">5.3 \u2014 Confirm No Oracle Processes Are Using the Home (Check Before Patching)<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># On STANDBY as oracle user\n# Check what processes are running from this ORACLE_HOME\nps -ef | grep $ORACLE_HOME | grep -v grep\n\n# You should see standby background processes (smon, pmon, etc.)\n# These are OK \u2014 OPatch can patch while the instance is mounted\n# OPatch will stop and restart them automatically during patching<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">5.4 \u2014 Apply Patch to Standby Oracle Home<\/h4>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd <strong>Why <code>opatch apply<\/code> while standby is mounted?<\/strong> OPatch is smart enough to handle a running Oracle instance during patching. It stops any Oracle processes that have open file handles on the files it needs to replace, replaces the files, then restarts those processes. The instance itself stays up in MOUNT state throughout.<\/p>\n<\/blockquote>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u26a0\ufe0f <strong>IMPORTANT:<\/strong> Run OPatch as the <code>oracle<\/code> user. Never run OPatch as root for the database home.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code># On STANDBY as oracle user\nsu - oracle\n\n# Navigate to patch directory\ncd \/stage\/patches\/unzipped\/&lt;PATCHNUM&gt;\n\n# Apply patch to standby Oracle Home\n# Note: No -local flag needed here \u2014 this is standalone (not RAC)\n$ORACLE_HOME\/OPatch\/opatch apply \\\n    -oh $ORACLE_HOME \\\n    -silent\n\n# Monitor progress in another terminal\ntail -100f \/tmp\/OPatch\/opatch_&lt;date&gt;_&lt;time&gt;.log<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Expected output:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Verifying environment and performing prerequisite checks...\nOPatch continues with these patches:   &lt;PATCHNUM&gt;\nDo you want to proceed? &#91;y|n]   (auto-answered yes with -silent)\nUser Responded with: Y\nBacking up files...\nPatching component oracle.rdbms, 19.x.x.x.x...\nPatching component oracle.rdbms.util, 19.x.x.x.x...\nPatch &lt;PATCHNUM&gt; successfully applied.\nLog file location: \/tmp\/OPatch\/opatch_&lt;date&gt;_&lt;time&gt;.log\nOPatch succeeded.<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u26a0\ufe0f <strong>IMPORTANT:<\/strong> If OPatch fails on standby \u2014 do NOT proceed to Phase 2. Run OPatch rollback on the standby to restore the original home, investigate the error, and fix it before retrying.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code># If patch fails \u2014 rollback on standby\n$ORACLE_HOME\/OPatch\/opatch rollback \\\n    -id &lt;PATCHNUM&gt; \\\n    -oh $ORACLE_HOME \\\n    -silent<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">5.5 \u2014 Verify Patch Applied Successfully on Standby<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># On STANDBY\nsu - oracle\n\n# Confirm patch is now in inventory\n$ORACLE_HOME\/OPatch\/opatch lsinventory | grep -E \"Oracle Database|Patch \"\n\n# Detailed check\n$ORACLE_HOME\/OPatch\/opatch lsinventory -detail | grep -A3 \"&lt;PATCHNUM&gt;\"<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">5.6 \u2014 Restart MRP on Standby<\/h4>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd <strong>Why?<\/strong> Now that the Oracle Home is patched, restart MRP with the new patched binaries. MRP will automatically catch up on all archivelogs that accumulated while it was stopped during patching.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On STANDBY\nsqlplus \/ as sysdba\n\n-- Start real-time apply with new patched binaries\nALTER DATABASE RECOVER MANAGED STANDBY DATABASE\n    USING CURRENT LOGFILE\n    DISCONNECT FROM SESSION;\n\n-- Verify MRP is running\nset linesize 180\nset pagesize 50\ncol process  for a12\ncol status   for a20\ncol sequence# for 999999\n\nSELECT process, status, sequence#\nFROM   v$managed_standby\nWHERE  process = 'MRP0';<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>What to look for:<\/strong> <code>MRP0<\/code> must show <code>APPLYING_LOG<\/code> or <code>WAIT_FOR_LOG<\/code>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">5.7 \u2014 Wait for Standby to Catch Up After Patching<\/h4>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd <strong>Why?<\/strong> During the time MRP was stopped, archivelogs accumulated on the standby but were not applied. Before proceeding to Phase 2 (switchover), confirm the standby has caught up and apply lag is near zero.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On STANDBY \u2014 monitor catch-up progress\n-- Run this repeatedly until apply lag is 0\n\nset linesize 200\nset pagesize 50\ncol name  for a30\ncol value for a40\ncol unit  for a20\n\nSELECT name, value, unit\nFROM   v$dataguard_stats\nWHERE  name IN ('transport lag', 'apply lag')\nORDER BY name;<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>-- Check last applied sequence number on standby\nset linesize 150\nset pagesize 50\n\nSELECT thread#, max(sequence#) last_applied\nFROM   v$log_history\nGROUP BY thread#;<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>-- Cross-check with primary \u2014 what is the last archived sequence on primary\n-- Run this on PRIMARY\nSELECT thread#, max(sequence#) last_archived\nFROM   v$archived_log\nWHERE  dest_id = 1\nGROUP BY thread#;<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u26a0\ufe0f <strong>IMPORTANT:<\/strong> Do not proceed to Phase 2 until apply lag is zero or near zero (within 1-2 minutes). Switching over with a large lag means the new primary (was standby) is missing recent transactions.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">5.8 \u2014 Verify Standby is Healthy After Phase 1<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>-- Connect to Broker from PRIMARY\ndgmgrl sys\/Oracle_123@ORCL\n\nDGMGRL&gt; SHOW CONFIGURATION;\n-- Must show: SUCCESS\n\nDGMGRL&gt; SHOW DATABASE VERBOSE 'ORCL_STBY';\n\n-- Validate standby is ready for switchover\nDGMGRL&gt; VALIDATE DATABASE 'ORCL_STBY';\n-- Look for: Ready for Switchover: Yes\n\nDGMGRL&gt; SHOW DATABASE 'ORCL_STBY' 'ApplyLagSecs';\n-- Should show 0 or very low number\n\nDGMGRL&gt; EXIT;<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd At this point: standby is on NEW patch level, primary is still on OLD patch level. Data Guard configuration is healthy in a mixed-patch state. This is supported and expected.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">6. Phase 2 \u2014 Switchover and datapatch<\/h3>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd <strong>What happens in Phase 2?<\/strong> We perform a planned switchover \u2014 the newly patched standby becomes the new primary, and the old primary becomes the new standby. Then we run datapatch on the new primary to update the data dictionary to the new patch level.<\/p>\n<\/blockquote>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd <strong>Application impact:<\/strong> During switchover, active application connections to the old primary will be disconnected. Applications must reconnect to the new primary. With proper connection pooling and SCAN\/service configuration, this reconnect happens automatically within seconds to a few minutes.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">6.1 \u2014 Pre-Switchover Final Checks<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>-- Connect to Broker on PRIMARY\ndgmgrl sys\/Oracle_123@ORCL\n\n-- Final configuration check\nDGMGRL&gt; SHOW CONFIGURATION;\n\n-- Final validation of standby\nDGMGRL&gt; VALIDATE DATABASE 'ORCL_STBY';<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>-- Check primary has no outstanding redo not yet shipped\n-- On PRIMARY\nsqlplus \/ as sysdba\n\nset linesize 200\nset pagesize 50\ncol dest_id for 999\ncol status  for a12\ncol error   for a45\n\n-- Archive dest 2 (standby) must be VALID and error-free\nSELECT dest_id, status, error,\n       target, archiver\nFROM   v$archive_dest\nWHERE  dest_id = 2;\n\n-- Confirm standby received latest archivelog\n-- Note the sequence number\nSELECT thread#, max(sequence#) last_on_primary\nFROM   v$archived_log\nWHERE  dest_id = 1\nGROUP BY thread#;<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On STANDBY \u2014 confirm same sequence is applied\nSELECT thread#, max(sequence#) last_applied\nFROM   v$log_history\nGROUP BY thread#;\n\n-- Both numbers must match before switchover<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">6.2 \u2014 Perform Switchover Using Broker<\/h4>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd <strong>Why Broker for switchover?<\/strong> Broker handles the entire switchover sequence automatically:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Flushes all remaining redo from primary to standby<\/li>\n\n\n\n<li>Converts primary role to standby<\/li>\n\n\n\n<li>Converts standby role to primary<\/li>\n\n\n\n<li>Opens new primary in READ WRITE mode<\/li>\n\n\n\n<li>Starts MRP on new standby (old primary)<br>All in one command with automatic error checking.<\/li>\n<\/ul>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>-- Connect to Broker on PRIMARY (connect before it becomes standby)\ndgmgrl sys\/Oracle_123@ORCL\n\n-- Perform switchover\n-- This takes 1-5 minutes depending on active sessions and redo in transit\nDGMGRL&gt; SWITCHOVER TO 'ORCL_STBY';\n\n-- Monitor switchover progress in Broker output\n-- You will see messages like:\n-- Performing switchover NOW, please wait...\n-- Operation requires a connection to database \"ORCL_STBY\"\n-- Switchover succeeded, new primary is \"ORCL_STBY\"<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd After switchover completes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>ORCL_STBY<\/code> (dbserver02) is now the <strong>NEW PRIMARY<\/strong> \u2014 running on PATCHED Oracle Home<\/li>\n\n\n\n<li><code>ORCL<\/code> (dbserver01) is now the <strong>NEW STANDBY<\/strong> \u2014 running on OLD (unpatched) Oracle Home<\/li>\n<\/ul>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>-- Verify new configuration\nDGMGRL&gt; SHOW CONFIGURATION;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Expected output after switchover:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Configuration - ORCL_DG_CONFIG\n\n  Protection Mode: MaxPerformance\n  Members:\n  ORCL_STBY - Primary database\n  ORCL      - Physical standby database\n\nConfiguration Status:\nSUCCESS<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>DGMGRL&gt; EXIT;<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">6.3 \u2014 Verify New Primary is Open and Healthy<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On dbserver02 (NEW PRIMARY \u2014 was standby)\nsqlplus \/ as sysdba\n\nset linesize 200\nset pagesize 50\ncol name           for a12\ncol db_unique_name for a15\ncol open_mode      for a15\ncol database_role  for a20\ncol log_mode       for a15\n\nSELECT name, db_unique_name, open_mode,\n       database_role, log_mode\nFROM   v$database;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Expected output:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>NAME    DB_UNIQUE_NAME  OPEN_MODE   DATABASE_ROLE    LOG_MODE\n------- --------------- ----------- ---------------- ------------\nORCL    ORCL_STBY       READ WRITE  PRIMARY          ARCHIVELOG<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">6.4 \u2014 Run datapatch on New Primary<\/h4>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u26a0\ufe0f <strong>IMPORTANT:<\/strong> datapatch must be run on the NEW PRIMARY (dbserver02 \u2014 was standby). The new primary is running the patched Oracle Home so datapatch will apply the SQL-level changes for the new patch. These changes replicate to the new standby (old primary) via redo automatically.<\/p>\n<\/blockquote>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd <strong>Why run datapatch only on the new primary?<\/strong> datapatch updates the data dictionary. In a Data Guard configuration the standby&#8217;s data dictionary is kept synchronized with the primary via redo apply. So you run datapatch on the primary and redo carries those changes to the standby automatically.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code># On dbserver02 (NEW PRIMARY) as oracle user\nsu - oracle\n\n# Set ORACLE_SID to the new primary SID\nexport ORACLE_SID=ORCL_STBY\n\n# Navigate to OPatch directory\ncd $ORACLE_HOME\/OPatch\n\n# Run datapatch on new primary\n.\/datapatch -verbose<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd Monitor datapatch log in another terminal:<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>ls -lrt \/u01\/app\/oracle\/cfgtoollogs\/sqlpatch\/\ntail -100f \/u01\/app\/oracle\/cfgtoollogs\/sqlpatch\/&lt;latest_dir&gt;\/&lt;latest&gt;.log\n\n# Convention B\nls -lrt \/oracle\/cfgtoollogs\/sqlpatch\/\ntail -100f \/oracle\/cfgtoollogs\/sqlpatch\/&lt;latest_dir&gt;\/&lt;latest&gt;.log<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Expected output:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Connecting to database...OK\nBootstrapping registry and package to current versions...done\nDetermining current state...done\nAdding patches to installation queue...done\nInstalling patches...\nPatch installation complete. Total patches installed: 1\nValidating logfiles...done\nPatch &lt;PATCHNUM&gt; apply: SUCCESS\ndatapatch: ALL PATCHES APPLIED SUCCESSFULLY.<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u26a0\ufe0f <strong>IMPORTANT:<\/strong> If datapatch fails \u2014 check the log for specific errors. Common issues:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Database not fully open \u2014 confirm <code>open_mode = READ WRITE<\/code><\/li>\n\n\n\n<li>TEMP tablespace full \u2014 extend it<\/li>\n\n\n\n<li>INVALID objects blocking compilation \u2014 run <code>@?\/rdbms\/admin\/utlrp.sql<\/code> first then rerun datapatch<\/li>\n<\/ul>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">6.5 \u2014 Verify datapatch Applied Successfully<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On NEW PRIMARY (dbserver02)\nsqlplus \/ as sysdba\n\nset linesize 200\nset pagesize 100\ncol patch_id    for 9999999999\ncol version     for a15\ncol status      for a15\ncol description for a55\ncol action_time for a25\n\nSELECT patch_id, version, status, description, action_time\nFROM   dba_registry_sqlpatch\nORDER BY action_time DESC;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>What to look for:<\/strong> Patch number shows with <code>SUCCESS<\/code> status.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">6.6 \u2014 Check for INVALID Objects on New Primary<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On NEW PRIMARY\nset linesize 180\nset pagesize 100\ncol owner       for a20\ncol object_name for a45\ncol object_type for a25\ncol status      for a10\n\nSELECT owner, object_name, object_type, status\nFROM   dba_objects\nWHERE  status = 'INVALID'\nORDER BY owner, object_type, object_name;\n\nSELECT COUNT(*) post_patch_invalid_count\nFROM   dba_objects\nWHERE  status = 'INVALID';<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>-- Recompile if count is higher than pre-patch baseline\n@?\/rdbms\/admin\/utlrp.sql\n\n-- Re-verify\nSELECT COUNT(*) FROM dba_objects WHERE status = 'INVALID';<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">6.7 \u2014 Verify All Components Are VALID on New Primary<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>set linesize 200\nset pagesize 100\ncol comp_name for a50\ncol version   for a15\ncol status    for a12\n\nSELECT comp_name, version, status\nFROM   dba_registry\nORDER BY comp_name;<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">7. Phase 3 \u2014 Patch Old Primary Oracle Home (Now Standby)<\/h3>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd <strong>What happens in Phase 3?<\/strong> The old primary (dbserver01) is now running as the standby database. Its Oracle Home is still on the OLD patch level. We now patch it to the same patch level as the new primary. This is done while the new primary continues serving applications \u2014 zero additional downtime.<\/p>\n<\/blockquote>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u26a0\ufe0f <strong>IMPORTANT:<\/strong> All steps in Phase 3 are performed on dbserver01 (OLD PRIMARY \u2014 NOW STANDBY) unless stated otherwise.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">7.1 \u2014 Verify New Standby (Old Primary) is Running and Receiving Redo<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On dbserver01 (NEW STANDBY \u2014 old primary)\nsqlplus \/ as sysdba\n\nset linesize 200\nset pagesize 50\ncol name           for a12\ncol db_unique_name for a15\ncol open_mode      for a15\ncol database_role  for a20\n\n-- Confirm it is now a standby\nSELECT name, db_unique_name, open_mode, database_role\nFROM   v$database;\n\n-- Check MRP is running and applying redo\nset linesize 180\nset pagesize 50\ncol process  for a12\ncol status   for a20\ncol sequence# for 999999\n\nSELECT process, status, sequence#\nFROM   v$managed_standby\nWHERE  process = 'MRP0';<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">7.2 \u2014 Stop MRP on New Standby (Old Primary)<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On dbserver01 (NEW STANDBY)\nsqlplus \/ as sysdba\n\n-- Stop MRP before patching\nALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;\n\n-- Confirm MRP stopped\nSELECT process, status FROM v$managed_standby WHERE process = 'MRP0';\n-- Should return no rows<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">7.3 \u2014 Apply Patch to Old Primary Oracle Home (Now Standby)<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># On dbserver01 (NEW STANDBY) as oracle user\nsu - oracle\n\n# Navigate to patch directory\ncd \/stage\/patches\/unzipped\/&lt;PATCHNUM&gt;\n\n# Apply patch to Oracle Home\n$ORACLE_HOME\/OPatch\/opatch apply \\\n    -oh $ORACLE_HOME \\\n    -silent\n\n# Monitor progress\ntail -100f \/tmp\/OPatch\/opatch_&lt;date&gt;_&lt;time&gt;.log<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Expected output:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Patching component oracle.rdbms, 19.x.x.x.x...\nPatch &lt;PATCHNUM&gt; successfully applied.\nOPatch succeeded.<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">7.4 \u2014 Verify Patch Applied Successfully on Old Primary Home<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># On dbserver01 (NEW STANDBY)\nsu - oracle\n$ORACLE_HOME\/OPatch\/opatch lsinventory | grep -E \"Oracle Database|Patch \"<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">7.5 \u2014 Restart MRP on New Standby<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On dbserver01 (NEW STANDBY)\nsqlplus \/ as sysdba\n\n-- Restart MRP with new patched binaries\nALTER DATABASE RECOVER MANAGED STANDBY DATABASE\n    USING CURRENT LOGFILE\n    DISCONNECT FROM SESSION;\n\n-- Verify MRP is running\nset linesize 180\nset pagesize 50\ncol process  for a12\ncol status   for a20\ncol sequence# for 999999\n\nSELECT process, status, sequence#\nFROM   v$managed_standby\nWHERE  process = 'MRP0';<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">7.6 \u2014 Wait for New Standby to Catch Up<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On dbserver01 (NEW STANDBY)\n-- Monitor catch-up progress \u2014 run repeatedly\nset linesize 200\nset pagesize 50\ncol name  for a30\ncol value for a40\ncol unit  for a20\n\nSELECT name, value, unit\nFROM   v$dataguard_stats\nWHERE  name IN ('transport lag','apply lag')\nORDER BY name;<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u26a0\ufe0f <strong>IMPORTANT:<\/strong> Wait for apply lag to reach 0 before performing any further operations or declaring patching complete.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">8. Optional \u2014 Switchover Back to Original Primary<\/h3>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd <strong>Why switchover back?<\/strong> After patching, some teams prefer to return the database to its original primary server (dbserver01). This is entirely optional \u2014 there is no technical reason the database cannot permanently run on dbserver02 as primary. Decide based on your team&#8217;s preference and documentation.<\/p>\n<\/blockquote>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd <strong>When to do this?<\/strong> Only after Phase 3 is complete and the new standby (old primary) has fully caught up. Both Oracle Homes are now on the same patch level so the switchover is completely clean.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>-- Connect to Broker on NEW PRIMARY (dbserver02)\ndgmgrl sys\/Oracle_123@ORCL_STBY\n\n-- Verify configuration is fully healthy\nDGMGRL&gt; SHOW CONFIGURATION;\nDGMGRL&gt; VALIDATE DATABASE 'ORCL';\n-- Ready for Switchover: Yes\n\n-- Switchover back to original primary\nDGMGRL&gt; SWITCHOVER TO 'ORCL';\n\n-- Verify configuration after switchover back\nDGMGRL&gt; SHOW CONFIGURATION;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Expected output after switchover back:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Configuration - ORCL_DG_CONFIG\n\n  Protection Mode: MaxPerformance\n  Members:\n  ORCL      - Primary database\n  ORCL_STBY - Physical standby database\n\nConfiguration Status:\nSUCCESS<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>DGMGRL&gt; EXIT;<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">9. Post-Patching Checks \u2014 Both Servers<\/h3>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u26a0\ufe0f <strong>IMPORTANT:<\/strong> Run all post-patch checks after Phase 3 completes (and after optional switchback if performed). These checks confirm both Oracle Homes are on the same patch level and Data Guard is fully healthy.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">9.1 \u2014 Confirm Patch Level is Same on Both Servers<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># On PRIMARY (whichever server is primary now)\nsu - oracle\n$ORACLE_HOME\/OPatch\/opatch lsinventory | grep -E \"Oracle Database|Patch \"\n\n# On STANDBY\nssh oracle@dbserver02 \\\n    \"$ORACLE_HOME\/OPatch\/opatch lsinventory | grep -E 'Oracle Database|Patch '\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Both must show the SAME patch number.<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">9.2 \u2014 Verify Data Guard Broker Configuration is Healthy<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>dgmgrl sys\/Oracle_123@ORCL\n\nDGMGRL&gt; SHOW CONFIGURATION;\n-- Must show: SUCCESS\n\nDGMGRL&gt; SHOW DATABASE VERBOSE 'ORCL';\nDGMGRL&gt; SHOW DATABASE VERBOSE 'ORCL_STBY';\n\nDGMGRL&gt; SHOW DATABASE 'ORCL_STBY' 'ApplyLagSecs';\nDGMGRL&gt; SHOW DATABASE 'ORCL_STBY' 'TransportLagSecs';\n\nDGMGRL&gt; VALIDATE DATABASE 'ORCL_STBY';\n\nDGMGRL&gt; EXIT;<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">9.3 \u2014 Check Database Roles and Open Mode on Both Servers<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On PRIMARY\nsqlplus \/ as sysdba\n\nset linesize 200\nset pagesize 50\ncol name            for a12\ncol db_unique_name  for a15\ncol open_mode       for a15\ncol database_role   for a20\ncol protection_mode for a22\n\nSELECT name, db_unique_name, open_mode,\n       database_role, protection_mode\nFROM   v$database;<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On STANDBY\nsqlplus \/ as sysdba\n\nSELECT name, db_unique_name, open_mode, database_role\nFROM   v$database;<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">9.4 \u2014 Verify New Version on Both Servers<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On PRIMARY\nsqlplus \/ as sysdba\n\nset linesize 150\nset pagesize 50\ncol banner for a80\n\nSELECT banner FROM v$version WHERE banner LIKE 'Oracle%';\n\nSELECT version, version_full FROM v$instance;<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On STANDBY (standby must be in MOUNT or READ ONLY state to query)\n-- Use v$instance which is always accessible\nSELECT version, version_full FROM v$instance;<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">9.5 \u2014 Verify datapatch Applied Successfully<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On PRIMARY only\nset linesize 200\nset pagesize 100\ncol patch_id    for 9999999999\ncol version     for a15\ncol status      for a15\ncol description for a55\ncol action_time for a25\n\nSELECT patch_id, version, status, description, action_time\nFROM   dba_registry_sqlpatch\nORDER BY action_time DESC;<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">9.6 \u2014 Check MRP Status and Apply Lag on Standby<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On STANDBY\nset linesize 200\nset pagesize 50\ncol process  for a12\ncol status   for a20\ncol sequence# for 999999\n\nSELECT process, status, sequence#\nFROM   v$managed_standby\nWHERE  process = 'MRP0';\n\nset linesize 200\ncol name  for a30\ncol value for a40\ncol unit  for a20\n\nSELECT name, value, unit\nFROM   v$dataguard_stats\nWHERE  name IN ('transport lag','apply lag')\nORDER BY name;<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">9.7 \u2014 Check Archive Destination on Primary is Error-Free<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On PRIMARY\nset linesize 200\nset pagesize 50\ncol dest_id   for 999\ncol dest_name for a20\ncol status    for a12\ncol error     for a50\n\nSELECT dest_id, dest_name, status, error\nFROM   v$archive_dest\nWHERE  dest_id IN (1,2)\nORDER BY dest_id;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>What to look for:<\/strong> Both destinations must show <code>VALID<\/code> with empty <code>error<\/code> column.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">9.8 \u2014 Check for Archive Log Gaps on Standby<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On STANDBY\nset linesize 150\nset pagesize 50\ncol low_sequence#  for 999999\ncol high_sequence# for 999999\n\n-- Should return no rows after successful patching\nSELECT thread#, low_sequence#, high_sequence#\nFROM   v$archive_gap;<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">9.9 \u2014 Check All Datafiles Online on Primary<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On PRIMARY\nset linesize 200\nset pagesize 100\ncol file#           for 999\ncol tablespace_name for a25\ncol status          for a12\ncol name            for a70\n\nSELECT file#, tablespace_name, status, name\nFROM   v$datafile\nORDER BY file#;<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">9.10 \u2014 Check Invalid Objects on Primary<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">sql<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On PRIMARY\nset linesize 180\nset pagesize 100\ncol owner       for a20\ncol object_name for a45\ncol object_type for a25\n\nSELECT owner, object_name, object_type, status\nFROM   dba_objects\nWHERE  status = 'INVALID'\nORDER BY owner, object_type, object_name;\n\nSELECT COUNT(*) final_invalid_count\nFROM   dba_objects\nWHERE  status = 'INVALID';<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">9.11 \u2014 Check All Components Are VALID on Primary<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>set linesize 200\nset pagesize 100\ncol comp_name for a50\ncol version   for a15\ncol status    for a12\n\nSELECT comp_name, version, status\nFROM   dba_registry\nORDER BY comp_name;<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">9.12 \u2014 Check Alert Logs on Both Servers<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># PRIMARY alert log\ntail -300 \/u01\/app\/oracle\/diag\/rdbms\/orcl\/ORCL\/trace\/alert_ORCL.log \\\n     | grep -E \"ORA-|Error|WARNING|Gap|ARC|MRP|switchover\"\n\n# Convention B primary alert log\ntail -300 \/oracle\/diag\/rdbms\/orcl\/ORCL\/trace\/alert_ORCL.log \\\n     | grep -E \"ORA-|Error|WARNING|Gap|ARC|MRP|switchover\"<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code># STANDBY alert log\nssh oracle@dbserver02 \\\n    \"tail -300 \/u01\/app\/oracle\/diag\/rdbms\/orcl_stby\/ORCL_STBY\/trace\/alert_ORCL_STBY.log \\\n     | grep -E 'ORA-|Error|WARNING|Gap|MRP|apply'\"\n\n# Convention B standby alert log\nssh oracle@dbserver02 \\\n    \"tail -300 \/oracle\/diag\/rdbms\/orcl_stby\/ORCL_STBY\/trace\/alert_ORCL_STBY.log \\\n     | grep -E 'ORA-|Error|WARNING|Gap|MRP|apply'\"<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">9.13 \u2014 End-to-End Redo Flow Verification<\/h4>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd <strong>Why?<\/strong> Force a log switch on the new primary and verify the archivelog is received and applied on the standby. This confirms the complete redo transport pipeline is working end-to-end with the new patched binaries on both sides.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On PRIMARY \u2014 force log switch\nsqlplus \/ as sysdba\nALTER SYSTEM SWITCH LOGFILE;\nALTER SYSTEM ARCHIVE LOG CURRENT;\n\n-- Note the sequence number\nSELECT thread#, max(sequence#) last_archived\nFROM   v$archived_log\nWHERE  dest_id = 1\nGROUP BY thread#;<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On STANDBY \u2014 wait 60 seconds then verify same sequence applied\nSELECT thread#, max(sequence#) last_applied\nFROM   v$log_history\nGROUP BY thread#;\n\n-- Sequence numbers must match<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">9.14 \u2014 Save Post-Patch Inventory from Both Servers<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># Save final inventory from PRIMARY\nsu - oracle\n$ORACLE_HOME\/OPatch\/opatch lsinventory \\\n    &gt; \/tmp\/post_patch_PRIMARY_$(date +%Y%m%d).txt\n\n# Save final inventory from STANDBY\nssh oracle@dbserver02 \\\n    \"$ORACLE_HOME\/OPatch\/opatch lsinventory\" \\\n    &gt; \/tmp\/post_patch_STANDBY_$(date +%Y%m%d).txt\n\n# Compare pre vs post for both servers\ndiff \/tmp\/pre_patch_PRIMARY_$(date +%Y%m%d).txt \\\n     \/tmp\/post_patch_PRIMARY_$(date +%Y%m%d).txt\n\ndiff \/tmp\/pre_patch_STANDBY_$(date +%Y%m%d).txt \\\n     \/tmp\/post_patch_STANDBY_$(date +%Y%m%d).txt<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">10. Patch Rollback Procedure for Data Guard<\/h3>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd <strong>When to use?<\/strong> If the patch causes critical issues after completing all phases. Rollback in DG is more complex because you need to rollback on both servers and coordinate the DG configuration.<\/p>\n<\/blockquote>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\ud83d\udcdd <strong>Rollback sequence:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>1. Run datapatch rollback on current PRIMARY\n2. Switchover back to original primary (if switched)\n3. Stop MRP on standby\n4. OPatch rollback on standby Oracle Home\n5. Restart MRP on standby\n6. OPatch rollback on primary Oracle Home\n7. Verify DG is healthy<\/code><\/pre>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">10.1 \u2014 Run datapatch Rollback on Current Primary<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>su - oracle\ncd $ORACLE_HOME\/OPatch\n\n# Rollback datapatch changes from data dictionary\n.\/datapatch -verbose -rollback &lt;PATCHNUM&gt;<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">10.2 \u2014 Stop MRP on Standby<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On STANDBY\nsqlplus \/ as sysdba\nALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">10.3 \u2014 OPatch Rollback on Standby Oracle Home<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># On STANDBY as oracle user\nsu - oracle\n\n$ORACLE_HOME\/OPatch\/opatch rollback \\\n    -id &lt;PATCHNUM&gt; \\\n    -oh $ORACLE_HOME \\\n    -silent<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">10.4 \u2014 Restart MRP on Standby After Rollback<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>-- On STANDBY\nsqlplus \/ as sysdba\nALTER DATABASE RECOVER MANAGED STANDBY DATABASE\n    USING CURRENT LOGFILE DISCONNECT FROM SESSION;<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">10.5 \u2014 OPatch Rollback on Primary Oracle Home<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># On PRIMARY as oracle user\nsu - oracle\n\n$ORACLE_HOME\/OPatch\/opatch rollback \\\n    -id &lt;PATCHNUM&gt; \\\n    -oh $ORACLE_HOME \\\n    -silent<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">10.6 \u2014 Verify Rollback and DG Health<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># Verify patch is removed from both homes\n$ORACLE_HOME\/OPatch\/opatch lsinventory | grep &lt;PATCHNUM&gt;\n# Should return no output\n\nssh oracle@dbserver02 \\\n    \"$ORACLE_HOME\/OPatch\/opatch lsinventory | grep &lt;PATCHNUM&gt;\"\n# Should return no output<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>-- Verify Broker configuration is healthy after rollback\ndgmgrl sys\/Oracle_123@ORCL\n\nDGMGRL&gt; SHOW CONFIGURATION;\nDGMGRL&gt; SHOW DATABASE 'ORCL_STBY' 'ApplyLagSecs';\nDGMGRL&gt; EXIT;<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>-- Verify datapatch rollback in data dictionary\nsqlplus \/ as sysdba\n\nSELECT patch_id, status, action_time\nFROM   dba_registry_sqlpatch\nORDER BY action_time DESC;\n-- Patch should show ROLLED BACK status<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">11. Quick Reference Card<\/h3>\n\n\n\n<figure class=\"wp-block-table has-small-font-size\"><table><thead><tr><th>Task<\/th><th>Command \/ Action<\/th><\/tr><\/thead><tbody><tr><td>Check current patch level<\/td><td><code>opatch lsinventory | grep -E \"Oracle Database|Patch \"<\/code><\/td><\/tr><tr><td>Check DG Broker health<\/td><td><code>dgmgrl&gt; SHOW CONFIGURATION;<\/code><\/td><\/tr><tr><td>Check apply lag<\/td><td><code>SELECT name,value FROM v$dataguard_stats WHERE name='apply lag';<\/code><\/td><\/tr><tr><td>Check archive gaps<\/td><td><code>SELECT thread#,low_sequence#,high_sequence# FROM v$archive_gap;<\/code><\/td><\/tr><tr><td>Check MRP status<\/td><td><code>SELECT process,status,sequence# FROM v$managed_standby WHERE process='MRP0';<\/code><\/td><\/tr><tr><td>Check archive dest<\/td><td><code>SELECT dest_id,status,error FROM v$archive_dest WHERE dest_id&lt;=2;<\/code><\/td><\/tr><tr><td>Stage patch on standby<\/td><td><code>scp patch.zip oracle@dbserver02:\/stage\/patches\/<\/code><\/td><\/tr><tr><td>Conflict check standby<\/td><td><code>opatch prereq CheckConflictAgainstOHWithDetail -ph &lt;PATCHDIR&gt;<\/code><\/td><\/tr><tr><td>Stop MRP<\/td><td><code>ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;<\/code><\/td><\/tr><tr><td>Patch standby home<\/td><td><code>opatch apply -oh $ORACLE_HOME -silent<\/code><\/td><\/tr><tr><td>Verify patch on standby<\/td><td><code>opatch lsinventory | grep Patch<\/code><\/td><\/tr><tr><td>Restart MRP<\/td><td><code>ALTER DATABASE RECOVER MANAGED STANDBY DATABASE USING CURRENT LOGFILE DISCONNECT;<\/code><\/td><\/tr><tr><td>Validate DG for switchover<\/td><td><code>dgmgrl&gt; VALIDATE DATABASE 'ORCL_STBY';<\/code><\/td><\/tr><tr><td>Perform switchover<\/td><td><code>dgmgrl&gt; SWITCHOVER TO 'ORCL_STBY';<\/code><\/td><\/tr><tr><td>Run datapatch (new primary)<\/td><td><code>.\/datapatch -verbose<\/code><\/td><\/tr><tr><td>Check datapatch result<\/td><td><code>SELECT patch_id,status FROM dba_registry_sqlpatch ORDER BY action_time DESC;<\/code><\/td><\/tr><tr><td>Check invalid objects<\/td><td><code>SELECT count(*) FROM dba_objects WHERE status='INVALID';<\/code><\/td><\/tr><tr><td>Recompile invalids<\/td><td><code>@?\/rdbms\/admin\/utlrp.sql<\/code><\/td><\/tr><tr><td>Check components<\/td><td><code>SELECT comp_name,status FROM dba_registry;<\/code><\/td><\/tr><tr><td>Patch old primary home<\/td><td><code>opatch apply -oh $ORACLE_HOME -silent<\/code> (on old primary now standby)<\/td><\/tr><tr><td>Verify both homes patched<\/td><td><code>opatch lsinventory | grep Patch<\/code> on both servers<\/td><\/tr><tr><td>Switchover back (optional)<\/td><td><code>dgmgrl&gt; SWITCHOVER TO 'ORCL';<\/code><\/td><\/tr><tr><td>Force log switch<\/td><td><code>ALTER SYSTEM SWITCH LOGFILE; ALTER SYSTEM ARCHIVE LOG CURRENT;<\/code><\/td><\/tr><tr><td>Check redo flow<\/td><td>Compare last archived (primary) vs last applied (standby) sequence<\/td><\/tr><tr><td>Save post inventory<\/td><td><code>opatch lsinventory &gt; \/tmp\/post_patch_$(date +%Y%m%d).txt<\/code><\/td><\/tr><tr><td>Rollback datapatch<\/td><td><code>.\/datapatch -verbose -rollback &lt;PATCHNUM&gt;<\/code><\/td><\/tr><tr><td>Rollback OPatch<\/td><td><code>opatch rollback -id &lt;PATCHNUM&gt; -oh $ORACLE_HOME -silent<\/code><\/td><\/tr><tr><td>Check DB role<\/td><td><code>SELECT db_unique_name,database_role,open_mode FROM v$database;<\/code><\/td><\/tr><tr><td>MOS DG Patching Guide<\/td><td>Doc ID 1265700.1<\/td><\/tr><tr><td>MOS DG Patch Best Practices<\/td><td>Doc ID 1599845.1<\/td><\/tr><tr><td>MOS 19c Patch Advisory<\/td><td>Doc ID 2694520.1<\/td><\/tr><tr><td>MOS OPatch Download<\/td><td>Doc ID 6880880.1<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">This SOP covers everything you need to patch Oracle Data Guard 19c on Linux using the standby-first rolling approach without referring to any other source. Always verify DG is fully healthy before starting, always patch standby first, always run datapatch only on the primary after all switchovers are complete, and always verify end-to-end redo flow after patching both Oracle Homes.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A complete production-ready SOP for patching Oracle Data Guard 19c on Linux. Covers the rolling patch method using the standby-first approach, Grid Infrastructure patching in DG environments, datapatch execution, switchover after patching, and full post-patch validation on both primary and standby \u2014 with real commands, expected outputs, and consultant-level notes for both standard OFA and [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":5785,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"googlesitekit_rrm_CAowu461DA:productID":"","footnotes":""},"categories":[1534],"tags":[],"class_list":["post-5767","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oracle-sop"],"_links":{"self":[{"href":"https:\/\/w3buddy.com\/blog\/wp-json\/wp\/v2\/posts\/5767","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/w3buddy.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/w3buddy.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/w3buddy.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/w3buddy.com\/blog\/wp-json\/wp\/v2\/comments?post=5767"}],"version-history":[{"count":2,"href":"https:\/\/w3buddy.com\/blog\/wp-json\/wp\/v2\/posts\/5767\/revisions"}],"predecessor-version":[{"id":5814,"href":"https:\/\/w3buddy.com\/blog\/wp-json\/wp\/v2\/posts\/5767\/revisions\/5814"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/w3buddy.com\/blog\/wp-json\/wp\/v2\/media\/5785"}],"wp:attachment":[{"href":"https:\/\/w3buddy.com\/blog\/wp-json\/wp\/v2\/media?parent=5767"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/w3buddy.com\/blog\/wp-json\/wp\/v2\/categories?post=5767"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/w3buddy.com\/blog\/wp-json\/wp\/v2\/tags?post=5767"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}