Who this is for: anyone troubleshooting an RDS performance incident with only Performance Insights turned on, staring at a query list that doesn’t explain why the instance feels slow.
During an incident where our API’s database calls were timing out intermittently, I pulled up Performance Insights expecting it to point straight at the offending query. It didn’t, because the queries running at the time weren’t unusually expensive; the instance itself was starved for memory from an unrelated batch process sharing the same host resources. Performance Insights showed me database activity. It couldn’t show me that the OS was swapping. That gap cost us close to forty minutes before someone suggested checking Enhanced Monitoring, which we hadn’t bothered enabling because we already had “monitoring” turned on.
Why This Matters
Performance Insights and Enhanced Monitoring answer two different questions, and the names don’t make that obvious. Performance Insights shows you what the database engine itself is doing: which queries are running, what they’re waiting on, lock contention, and how load breaks down by SQL statement. Enhanced Monitoring shows you what the operating system underneath the engine is doing: CPU, memory, disk I/O, and individual OS processes, collected by an agent running on the instance rather than pulled from the hypervisor the way standard CloudWatch metrics are. If your bottleneck is a bad query, Performance Insights finds it fast. If your bottleneck is memory pressure, disk contention, or a noisy neighbor process at the OS level, Performance Insights won’t show it, because it’s simply not looking at that layer.
What we were missing during the incident
Standard CloudWatch CPU utilization metrics come from the hypervisor level and update on a coarser interval. Enhanced Monitoring’s OS-level metrics update with up to one-second granularity and break down memory, swap usage, and per-process CPU and disk activity in a level of detail CloudWatch’s standard metrics never show. Our memory pressure issue was exactly the kind of thing that’s invisible without it: aggregate CPU looked fine, Performance Insights showed normal query load, and the actual problem (a background job quietly consuming memory the database engine needed) only showed up once we had OS-level visibility.
Turning on Enhanced Monitoring
Enhanced Monitoring needs an IAM role RDS uses to publish metrics into CloudWatch Logs, and a granularity setting for how often the agent collects data.
aws iam create-role \ --role-name rds-enhanced-monitoring-role \ --assume-role-policy-document file://monitoring-trust-policy.jsonaws iam attach-role-policy \ --role-name rds-enhanced-monitoring-role \ --policy-arn arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRoleaws rds modify-db-instance \ --db-instance-identifier api-primary \ --monitoring-interval 1 \ --monitoring-role-arn arn:aws:iam::123456789012:role/rds-enhanced-monitoring-role \ --apply-immediately
A monitoring-interval of 1 gives you one-second granularity, the finest available and what you want for actually diagnosing an active incident; the tradeoff is a bit more log volume in CloudWatch Logs, which is a real but usually minor cost compared to the diagnostic value during an incident. Once enabled, the OS metrics land in the RDSOSMetrics log group in CloudWatch Logs, not as standard CloudWatch metrics, which is a detail that trips people up if they go looking for them in the regular metrics console instead of Logs Insights.
Using both together during an incident
The workflow that actually works: start with Enhanced Monitoring to figure out whether you’re CPU-bound, memory-bound, or I/O-bound at the OS level, then switch to Performance Insights to find the specific query or session responsible once you know which resource is actually constrained. Going straight to Performance Insights, which is the instinctive first move for most DBAs because it feels closer to “the database,” skips the step that would have told us our problem wasn’t a query at all.
Where This Requires Care
Enhanced Monitoring at one-second granularity generates meaningfully more CloudWatch Logs volume than a longer interval; on a large fleet, that’s a real, if usually small, cost line item worth being aware of rather than surprised by on a bill.
The OS-level metrics are specific to the instance’s host resources. On engines or configurations where you share underlying infrastructure differently, interpret per-process breakdowns with that context in mind rather than assuming perfect isolation.
Neither tool replaces the other; they answer different layers of the same question. Don’t turn off Performance Insights because you’ve enabled Enhanced Monitoring, or vice versa. Incident diagnosis is faster with both available than with either alone.
Enhanced Monitoring needs to already be enabled before an incident to be useful during one; you can’t retroactively see OS metrics from before you turned it on. Enable it proactively on anything you’d actually need to troubleshoot under pressure.
Quick Reference
- Performance Insights shows database engine activity (queries, waits, locks); Enhanced Monitoring shows OS-level activity (CPU, memory, disk, processes) via an on-instance agent.
- Enhanced Monitoring data lands in the RDSOSMetrics CloudWatch Logs group, not standard CloudWatch metrics; look in Logs Insights, not the metrics console.
- During an incident, start with Enhanced Monitoring to identify whether you’re CPU, memory, or I/O bound, then use Performance Insights to pinpoint the specific query or session.
- Enable Enhanced Monitoring proactively; you can’t retroactively see OS-level history from before it was turned on.
- Use both tools together; they cover different layers and neither substitutes for the other.
My Take
I’d had Performance Insights enabled everywhere for over a year and genuinely believed that counted as full monitoring coverage. It doesn’t, and the gap only becomes obvious the moment your actual bottleneck happens to live at the OS layer instead of the query layer. Enhanced Monitoring is cheap enough and simple enough to enable that there’s little reason to leave it off any instance you’d actually need to debug quickly. The forty minutes we lost during that incident is exactly the cost of assuming one monitoring tool covers everything.

