Skip to content

RDS databases and clusters should not use a database engine default port

Default database ports are the first thing automated scanners and attackers probe. Running MySQL on 3306 or PostgreSQL on 5432 means every bot on the internet already knows where to knock. Changing the port does not replace proper network controls, but it drops your database from bulk scans and cuts noise in security logs.

Security-in-depth means removing easy signals. A non-default port combined with security group restrictions and private subnets makes unauthorized discovery meaningfully harder.

Retrofit consideration

Changing the port on a running RDS instance or Aurora cluster forces a reboot and requires updating every application connection string, security group rule, and DNS-based service discovery entry. Plan a maintenance window and coordinate with all consumers.

Implementation

Choose the approach that matches how you manage Terraform.

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_rds_cluster, port must not match the engine default: 3306 for aurora-mysql/aurora, 5432 for aurora-postgresql. For aws_db_instance, the same applies: 3306 for mysql and mariadb, 5432 for postgres, 1433 for sqlserver-*, 1521 for oracle-*. Omitting port fails the control because Terraform and AWS assign the engine default. An explicit value that matches the default also fails. To pass, set port to a custom value (3307 for MySQL and 5433 for PostgreSQL are common choices) and update security group rules to match.

Common pitfalls

  • Omitting the port argument defaults to engine port

    Terraform passes no port value to AWS unless you set it explicitly, so AWS assigns the engine default. The control flags this as non-compliant regardless of intent. Always set port on both aws_db_instance and aws_rds_cluster.

  • Read replicas inherit the source port

    Read replicas created via replicate_source_db inherit the source instance's port. If the primary is still on the default, the replica will be too. Fix the source first, or set port explicitly on the replica (which forces recreation).

  • Security group rules must match the new port

    Connectivity breaks immediately if port changes without matching updates to from_port and to_port in aws_security_group_rule or aws_vpc_security_group_ingress_rule. Update both in the same apply.

  • Aurora cluster vs. instance port mismatch

    Aurora port is a cluster-level setting. Set it on aws_rds_cluster, not on aws_rds_cluster_instance. Setting port on individual instance resources has no effect; the cluster value propagates to all instances automatically.

  • Snapshot restores can carry forward prior port settings

    Set port explicitly on any resource restored from a snapshot. Terraform will otherwise carry forward whatever port the snapshot captured, which is likely the engine default if the source was never remediated.

Audit evidence

Config rule evaluation results showing all RDS instances and Aurora clusters as COMPLIANT are the primary artifact. The RDS console port field on each instance or cluster detail page works as direct visual confirmation. Prowler output listing each resource and its configured port is a clean, exportable alternative. Organizations using Security Hub can pull the finding status across accounts and regions as consolidated proof.

Tool mappings

Use these identifiers to cross-reference this control across tools, reports, and evidence.

  • Compliance.tf Control: rds_db_instance_and_cluster_no_default_port

  • Powerpipe Control: aws_compliance.control.rds_db_instance_and_cluster_no_default_port

  • Prowler Checks: rds_cluster_non_default_port, rds_instance_non_default_port

  • AWS Security Hub Control: RDS.23

  • KICS Query: bca7cc4d-b3a4-4345-9461-eb69c68fcd26

Last reviewed: 2026-03-09