Task timed out after 3.00 seconds

Lambda to RDS Timeout in VPC: NAT Gateway or Security Group Fix

Your Lambda can't reach RDS because it's stuck in a private subnet with no NAT gateway, or the security groups don't trust each other. Here's the actual fix.

You deploy a Lambda function, attach it to a VPC so it can reach your RDS instance, hit Invoke, and wait. Three seconds later: Task timed out after 3.00 seconds. No stack trace pointing at the database. No helpful error. The function just... stops. I've seen this bite people at 2am during a production deploy more times than I can count, and it almost always comes down to one of two things: the Lambda has no route to the outside world, or the security groups aren't letting traffic through.

Why this happens

When you attach a Lambda function to a VPC, you're taking away its default internet access. That's the part everyone forgets. A Lambda outside a VPC runs on AWS-managed infrastructure with full outbound connectivity. The moment you put it in a private subnet, it only has what that subnet's route table gives it.

If your RDS instance is in the same VPC, in theory the Lambda should reach it over the private network. And it will — if the security groups allow it. If your RDS is publicly accessible (or you're using an RDS proxy endpoint that resolves to a public IP), the Lambda needs a NAT gateway to reach it. Without one, the connection attempt just hangs until the timeout fires.

Two failure modes, same symptom:

  1. No NAT gateway. Lambda is in a private subnet with a route table that only knows about local. Any attempt to reach a public IP, including a public RDS endpoint, silently dies.
  2. Security group mismatch. The Lambda's SG doesn't allow outbound to the RDS port, or the RDS SG doesn't allow inbound from the Lambda's SG. Traffic gets dropped, connection stalls, timeout.
Quick sanity check: the default timeout on a new Lambda is 3 seconds. Even a healthy database connection can take longer than that on a cold start. Bump it to 30 seconds while you're debugging so you're not chasing a red herring.

The fix

Work through these in order. Don't skip steps — the second one depends on the first.

  1. Confirm the Lambda is in a private subnet. In the Lambda console, go to Configuration → VPC. Check the subnet IDs. If they're public subnets (the ones with an Internet Gateway route), you've got a different problem and you should move the Lambda to private subnets anyway — that's the correct architecture.
  2. Check the route table on those subnets. Go to VPC → Route Tables and find the one associated with your Lambda's subnets. Look for a 0.0.0.0/0 route. If the target is igw-xxxx (Internet Gateway), your Lambda is in a public subnet. If the target is nat-xxxx (NAT Gateway), you're fine for internet access. If there's no 0.0.0.0/0 route at all, that's your problem.
    aws ec2 describe-route-tables \
      --filters "Name=association.subnet-id,Values=subnet-abc123" \
      --query 'RouteTables[].Routes'
  3. Add a NAT gateway if it's missing. You need one per AZ if you want high availability, but for dev, one is fine. Create it in a public subnet, allocate an Elastic IP, then add a route in your private subnet's route table:
    Destination: 0.0.0.0/0
    Target: nat-0123456789abcdef0
    NAT gateways cost about $0.045/hour plus data processing. If you're just testing, remember to tear it down.
  4. Fix the security groups. This is the one people miss. Your Lambda needs an outbound rule allowing traffic to the RDS port (3306 for MySQL, 5432 for Postgres, 1433 for SQL Server). The RDS security group needs an inbound rule that references the Lambda's security group — not a CIDR range. Referencing the SG is cleaner and survives IP changes.
    RDS SG inbound rule:
      Type: MySQL/Aurora
      Port: 3306
      Source: sg-
    Don't just open it to 0.0.0.0/0. That's how you end up on the wrong end of a security audit.
  5. Skip the VPC entirely if you don't need it. If your RDS instance is publicly accessible and you can lock it down by IP, you can run the Lambda outside a VPC. No NAT gateway, no cold start penalty from ENI attachment, no route table headaches. It's a legit option for small workloads. The tradeoff is exposing RDS to the internet, which most teams won't accept.
  6. Use RDS Proxy if you're scaling. Lambda + RDS without a proxy means every concurrent invocation opens a new connection. MySQL and Postgres will run out of connection slots fast. RDS Proxy pools connections and lives in your VPC, so your Lambda just talks to the proxy endpoint. This doesn't fix the NAT gateway problem, but it fixes the "why does this work at 5 invocations and fail at 50" problem you'll hit next.

If it's still timing out

Work through these in order:

  • Bump the timeout past 3 seconds. Set it to 30 seconds while debugging. A 3-second timeout can't tell the difference between "can't connect" and "slow to connect."
  • Check the RDS endpoint. If you're using the cluster endpoint for Aurora, make sure the writer endpoint is the one your Lambda needs for writes. Reader endpoints will reject writes and can behave oddly on writes-through-a-reader.
  • Verify NACLs. Network ACLs are stateless and easy to forget. If someone added a deny rule to the subnet's NACL, traffic dies before it reaches the security group. Check both inbound and outbound on the NACL for the Lambda subnet and the RDS subnet.
  • Look at VPC Flow Logs. Enable them on the Lambda's ENI and the RDS ENI. A REJECT entry tells you exactly which SG or NACL dropped the packet. This is the fastest way to stop guessing.
  • Test from a bastion in the same subnet. SSH into an EC2 instance in the Lambda's subnet and try telnet 3306. If that fails too, the problem is network-level, not Lambda-specific.
  • Check for RDS maintenance windows. If the function worked yesterday and fails today, look at the RDS event log. A pending reboot or a failover will cause exactly this symptom.

The 90% case is the missing NAT gateway route. The other 10% is a security group that references the wrong source. Check those two first, and you'll save yourself an afternoon of staring at CloudWatch logs.

Related Errors in Server & Cloud
0X000013A7 Cluster log won't write: 0x000013A7 error fix TASK ERROR: can't lock file '/var/lock/qemu-server/lock-XXX.conf' - got timeout Proxmox VM Won't Start: Configuration Error Fix Cloud SQL Restart Loop: Fix for MySQL 8.0 on GCP 0X00001F46 FRS_ERR_SERVICE_COMM (0X00001F46): File Replication Service Won't Start

Was this solution helpful?

EP
Erropedia Team
Tech Support Editors
The Erropedia editorial team researches and documents real-world tech errors from across Windows, Linux, macOS, networking, databases, cloud platforms, and more. Every solution is reviewed for accuracy and updated as software and systems evolve.