RDS DB instances and clusters should have enhanced monitoring enabled
Standard CloudWatch metrics for RDS are collected at the hypervisor level and report at one-minute granularity at best. Enhanced monitoring runs an agent directly on the DB instance's OS, providing per-second granularity on metrics like process lists, memory breakdowns, and swap usage. This difference matters when diagnosing intermittent performance issues or resource contention that hypervisor-level metrics miss entirely.
During an outage, the gap between "the database seems slow" and "the database is swapping because a background process consumed all available memory" can cost hours. Enhanced monitoring closes that gap with data you can actually act on.
Retrofit consideration
You'll need an IAM role with the AmazonRDSEnhancedMonitoringRole policy before enabling this. Existing instances can be modified without downtime, but the API call triggers a brief metadata update, so plan for it in change windows if your organization tracks them.
Implementation
Choose the approach that matches how you manage Terraform.
Use the compliance.tf module to enforce this control by default. See get started with compliance.tf.
module "rds" {
source = "hipaa.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "nist80053.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "nistcsf.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "fedrampmoderate.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "nist800171.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "cisacyberessentials.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "nydfs23.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "ffiec.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "rbiitfnbfc.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "fedramplow.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "nistcsfv11.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "nist80053rev4.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
If you use terraform-aws-modules/rds/aws, set the right module inputs for this control. You can later migrate to the compliance.tf module with minimal changes because it is compatible by design.
module "rds" {
source = "terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
Use AWS provider resources directly. See docs for the resources involved: aws_db_instance.
resource "aws_db_instance" "this" {
allocated_storage = 20
enabled_cloudwatch_logs_exports = ["general", "slowquery"]
engine = "mysql"
identifier = "pofix-abc123"
instance_class = "db.t3.micro"
monitoring_interval = 60
monitoring_role_arn = "arn:aws:iam::123456789012:role/example-role"
password = "ChangeMe123!"
skip_final_snapshot = true
username = "dbadmin"
}
What this control checks
For aws_db_instance resources, monitoring_interval must be set to a supported non-zero value: 1, 5, 10, 15, 30, or 60 (seconds). A value of 0 or an omitted argument disables enhanced monitoring and fails this control. monitoring_role_arn should reference an IAM role with the AmazonRDSEnhancedMonitoringRole managed policy attached. For Aurora, the same arguments apply on each aws_rds_cluster_instance resource. The aws_rds_cluster resource itself does not have these arguments; monitoring is configured per cluster instance. If you set monitoring_interval without monitoring_role_arn, RDS may use or create the default enhanced monitoring role (rds-monitoring-role) if permissions allow. Specify the role explicitly to keep IAM behavior predictable and auditable.
Common pitfalls
Cluster vs. cluster instance confusion
Applying
monitoring_intervaltoaws_rds_clusterproduces a Terraform validation error and leaves cluster instances unmonitored. Enhanced monitoring is configured on eachaws_rds_cluster_instance, not the cluster resource itself.Missing or incorrect IAM role
If
monitoring_role_arnpoints to a role without theAmazonRDSEnhancedMonitoringRolemanaged policy, theModifyDBInstanceAPI call fails at apply time. Omit the argument entirely and RDS will try to use or create the defaultrds-monitoring-role, which breaks silently in accounts where SCPs restrict role creation or assumption.Interval value validation
The valid values for
monitoring_intervalare 0, 1, 5, 10, 15, 30, and 60. An arbitrary integer like 2 or 120 will passterraform planand then fail at apply with anInvalidParameterValueerror from the RDS API. There's no plan-time warning.CloudWatch Logs cost at 1-second granularity
A 1-second interval generates a CloudWatch Logs event every second per instance. On a fleet of dozens of RDS instances, ingestion and storage costs accumulate quickly. For most compliance use cases, 60 seconds is sufficient and the cost difference is significant.
Audit evidence
An auditor expects Config rule evaluation results from the managed rule rds-enhanced-monitoring-enabled, showing all RDS instances as COMPLIANT. Console screenshots of the "Enhanced monitoring" tab on individual DB instances with active OS-level metrics (CPU, memory, swap, disk I/O) confirm the agent is reporting. CloudWatch Logs entries for RDS Enhanced Monitoring metrics work as a durable record of collected data.
For population-level coverage, a Config conformance pack report or a CSPM scan listing all evaluated RDS resources and their monitoring intervals gives auditors confidence that no instances were missed.
Framework-specific interpretation
HIPAA Omnibus Rule 2013: 45 CFR 164.312(b) requires audit controls on information systems handling ePHI, and 164.308(a)(1)(ii)(D) calls for regular review of system activity. For covered entities running ePHI workloads on RDS, enhanced monitoring provides the OS-level visibility that makes those reviews meaningful rather than perfunctory.
NIST SP 800-53 Rev 5: Hypervisor-level CloudWatch metrics don't give you process-level visibility into what's running on a database instance. SI-4 requires monitoring that can detect attacks and indicators of potential attacks, and CA-7 calls for continuous monitoring of system components. The per-second OS metrics from enhanced monitoring feed into both the anomaly detection and capacity management workflows these controls require.
NIST Cybersecurity Framework v2.0: Enhanced monitoring feeds directly into DE.CM under the Detect function. Per-second OS metrics from RDS instances give you the signal density DE.CM expects for identifying anomalous conditions before they become incidents.
FedRAMP Moderate Baseline Rev 4: CA-7 and SI-4 both require ongoing visibility into system behavior within the authorization boundary. At the Moderate baseline, that means collecting OS-level metrics from database instances, not just hypervisor-level data from CloudWatch. Enhanced monitoring is how you get there.
Related controls
Tool mappings
Use these identifiers to cross-reference this control across tools, reports, and evidence.
Compliance.tf Control:
rds_db_instance_and_cluster_enhanced_monitoring_enabledAWS Config Managed Rule:
RDS_ENHANCED_MONITORING_ENABLEDCheckov Check:
CKV_AWS_118Powerpipe Control:
aws_compliance.control.rds_db_instance_and_cluster_enhanced_monitoring_enabledProwler Checks:
rds_instance_enhanced_monitoring_enabled,rds_instance_extended_supportAWS Security Hub Control:
RDS.6
Last reviewed: 2026-03-09