AWS
Cloud Infrastructure
Tutorials

AWS Lambda Python 3.9 End-of-Support: Find and Upgrade Every Affected Function

You probably got the AWS Health notification about Python 3.9 end-of-support and thought you had time. Here's the thing: the deadline already passed. As of December 15, 2025, AWS stopped applying security patches to the python3.9 runtime. Every day your functions stay on Python 3.9, they're running unpatched code in production.
The good news is that your functions still work. The bad news is that AWS will block function creates on August 31, 2026 and block updates on September 30, 2026, so you're on borrowed time for making changes too. With functions scattered across dozens of accounts and regions, clicking through the AWS Console to find them all doesn't scale. This post gives you the SQL queries to identify every affected function, prioritize the risky ones, and plan your migration.

What Is the Python 3.9 Deprecation Timeline? #

Python 3.9 reached community end-of-life on October 5, 2025. AWS follows upstream EOL with its own phased deprecation for Lambda runtimes:
December 15, 2025 (already passed): AWS stopped applying security patches to python3.9. Functions using this runtime lost technical support eligibility. This is where we are right now - your Python 3.9 functions are running without security updates.
August 31, 2026: You won't be able to create new Lambda functions using python3.9. Existing functions keep running.
September 30, 2026: You won't be able to update existing functions using python3.9. This is the hard deadline - after this, you're locked out of code and configuration changes.
And Python 3.9 isn't the only one. Here's the current state of Python runtimes in Lambda:
RuntimeIdentifierOSEnd of SupportBlock CreateBlock Update
Python 3.13python3.13Amazon Linux 2023Jun 30, 2029Jul 31, 2029Aug 31, 2029
Python 3.12python3.12Amazon Linux 2023Oct 31, 2028Nov 30, 2028Jan 10, 2029
Python 3.11python3.11Amazon Linux 2Jun 30, 2027Jul 31, 2027Aug 31, 2027
Python 3.10python3.10Amazon Linux 2Oct 31, 2026Nov 30, 2026Jan 15, 2027
Python 3.9python3.9Amazon Linux 2Dec 15, 2025Aug 31, 2026Sep 30, 2026
Python 3.8python3.8Amazon Linux 2Oct 14, 2024Aug 31, 2026Sep 30, 2026

What Do I Need to Run These Queries? #

  • CloudQuery CLI - Download here, or use CloudQuery Platform for a managed experience
  • PostgreSQL database - any PostgreSQL instance works as the sync destination
  • AWS credentials - configured for each account you want to audit (see the AWS plugin docs for multi-account setup)
That's it. The queries below work against the synced data, so you don't need direct AWS access to run them after the initial sync.

How Do I Find All Affected Lambda Functions? #

The AWS CLI requires you to query each region separately with aws lambda list-functions --region us-east-1 --query "Functions[?Runtime=='python3.9']". With dozens of accounts across multiple regions, that approach falls apart fast.
CloudQuery syncs your Lambda function data into a SQL database, letting you query across all accounts and regions in one shot. If you already have CloudQuery running, skip to the queries below. If not, here's the minimal configuration file to get started:
kind: source
spec:
  name: aws
  path: cloudquery/aws
  registry: cloudquery
  version: 'v32.48.3'
  tables: ['aws_lambda_functions']
  destinations: ['postgresql']
---
kind: destination
spec:
  name: postgresql
  path: cloudquery/postgresql
  registry: cloudquery
  version: 'v8.13.1'
  spec:
    connection_string: ${PG_CONNECTION_STRING}
Run the sync:
cloudquery sync config.yml
CloudQuery calls AWS Lambda's ListFunctions API across all configured accounts and regions, pulling configuration data including the Runtime field into the aws_lambda_functions table.

Find Every Python 3.9 Function #

SELECT
    account_id,
    region,
    configuration->>'FunctionName' AS function_name,
    configuration->>'Runtime' AS runtime,
    configuration->>'LastModified' AS last_modified,
    arn
FROM
    aws_lambda_functions
WHERE
    configuration->>'Runtime' = 'python3.9'
ORDER BY
    account_id, region, function_name;

Count by Account and Region #

This gives you a quick read on which accounts and regions have the most work ahead:
SELECT
    account_id,
    region,
    COUNT(*) AS affected_functions
FROM
    aws_lambda_functions
WHERE
    configuration->>'Runtime' = 'python3.9'
GROUP BY
    account_id, region
ORDER BY
    affected_functions DESC;

Audit All Deprecated and Near-EOL Runtimes at Once #

If you're already running this audit, you probably have stragglers from older deprecations too. This query flags every Lambda function running a deprecated or soon-to-be-deprecated runtime:
SELECT
    account_id,
    region,
    configuration->>'FunctionName' AS function_name,
    configuration->>'Runtime' AS runtime,
    CASE
        WHEN configuration->>'Runtime' IN ('python2.7', 'python3.6', 'python3.7') THEN 'Deprecated - Updates Blocked'
        WHEN configuration->>'Runtime' IN ('python3.8', 'python3.9') THEN 'Deprecated - Unpatched'
        WHEN configuration->>'Runtime' IN ('nodejs14.x', 'nodejs16.x') THEN 'Deprecated - Updates Blocked'
        WHEN configuration->>'Runtime' = 'nodejs18.x' THEN 'Deprecated - Unpatched'
        WHEN configuration->>'Runtime' = 'dotnet6' THEN 'Deprecated - Unpatched'
        WHEN configuration->>'Runtime' = 'java8' THEN 'Deprecated - Updates Blocked'
        ELSE 'Supported'
    END AS status,
    arn
FROM
    aws_lambda_functions
WHERE
    configuration->>'Runtime' IN (
        'python2.7', 'python3.6', 'python3.7', 'python3.8', 'python3.9',
        'nodejs14.x', 'nodejs16.x', 'nodejs18.x',
        'dotnet6', 'java8'
    )
ORDER BY
    status, runtime, account_id;

How Do I Prioritize Functions for Migration? #

Finding affected functions is step one. Step two is figuring out which ones to fix first. Not every Lambda function carries the same risk - a production payment processor running unpatched Python 3.9 needs attention before a dev account's test function. Here are several queries to help you triage.

By Environment Tags (Production First) #

Most teams tag functions with environment labels. If your tagging is consistent, this is the fastest way to find what matters:
SELECT
    account_id,
    region,
    configuration->>'FunctionName' AS function_name,
    tags->>'Environment' AS environment,
    tags->>'Team' AS team,
    arn
FROM
    aws_lambda_functions
WHERE
    configuration->>'Runtime' = 'python3.9'
    AND (
        tags->>'Environment' ILIKE '%prod%'
        OR tags->>'Environment' ILIKE '%production%'
    )
ORDER BY
    account_id, region;

By VPC Configuration (Connected to Private Infrastructure) #

Functions attached to a VPC are usually accessing private resources like RDS databases or internal services. That's a signal they're doing something important:
SELECT
    account_id,
    region,
    configuration->>'FunctionName' AS function_name,
    configuration->'VpcConfig'->>'VpcId' AS vpc_id,
    configuration->>'MemorySize' AS memory_mb,
    arn
FROM
    aws_lambda_functions
WHERE
    configuration->>'Runtime' = 'python3.9'
    AND configuration->'VpcConfig'->>'VpcId' IS NOT NULL
    AND configuration->'VpcConfig'->>'VpcId' != ''
ORDER BY
    account_id, region;

By Resource Allocation (Bigger Functions = More Critical) #

Functions with higher memory and longer timeouts tend to be doing heavier work. A 3 GB function with a 15-minute timeout is probably processing something important:
SELECT
    account_id,
    region,
    configuration->>'FunctionName' AS function_name,
    (configuration->>'MemorySize')::integer AS memory_mb,
    (configuration->>'Timeout')::integer AS timeout_seconds,
    arn
FROM
    aws_lambda_functions
WHERE
    configuration->>'Runtime' = 'python3.9'
ORDER BY
    memory_mb DESC, timeout_seconds DESC;

By Last Modified Date (Recently Updated = Actively Used) #

Functions that were recently modified are actively maintained. Functions that haven't been touched in years might be candidates for deletion rather than migration:
SELECT
    account_id,
    region,
    configuration->>'FunctionName' AS function_name,
    configuration->>'LastModified' AS last_modified,
    CASE
        WHEN (configuration->>'LastModified')::timestamptz > NOW() - INTERVAL '90 days' THEN 'Active'
        WHEN (configuration->>'LastModified')::timestamptz > NOW() - INTERVAL '365 days' THEN 'Stale'
        ELSE 'Abandoned'
    END AS activity_status,
    arn
FROM
    aws_lambda_functions
WHERE
    configuration->>'Runtime' = 'python3.9'
ORDER BY
    last_modified DESC;

Combined Priority Score #

This query pulls together multiple signals into a single prioritized view. Higher-memory, VPC-attached, recently modified functions with production tags rise to the top:
SELECT
    account_id,
    region,
    configuration->>'FunctionName' AS function_name,
    configuration->>'Runtime' AS runtime,
    (configuration->>'MemorySize')::integer AS memory_mb,
    (configuration->>'Timeout')::integer AS timeout_seconds,
    configuration->'VpcConfig'->>'VpcId' AS vpc_id,
    configuration->>'LastModified' AS last_modified,
    tags->>'Environment' AS environment,
    tags->>'Team' AS team,
    CASE
        WHEN tags->>'Environment' ILIKE '%prod%' THEN 3
        WHEN tags->>'Environment' ILIKE '%stag%' THEN 2
        ELSE 1
    END
    + CASE WHEN configuration->'VpcConfig'->>'VpcId' IS NOT NULL
           AND configuration->'VpcConfig'->>'VpcId' != '' THEN 2 ELSE 0 END
    + CASE WHEN (configuration->>'MemorySize')::integer >= 1024 THEN 1 ELSE 0 END
    + CASE WHEN (configuration->>'LastModified')::timestamptz > NOW() - INTERVAL '90 days' THEN 1 ELSE 0 END
    AS priority_score,
    arn
FROM
    aws_lambda_functions
WHERE
    configuration->>'Runtime' = 'python3.9'
ORDER BY
    priority_score DESC, memory_mb DESC;

What Are the Python 3.12 and 3.13 Upgrade Paths? #

Python 3.12 and 3.13 are both solid choices. The right one depends on how aggressive you want to be with the upgrade.
Python 3.12 runs on Amazon Linux 2023, is well-tested in Lambda environments, and has support through October 2028. It's the safer choice if you want stability and a wide compatibility window. Python 3.12 has been available in Lambda since December 2023, so the ecosystem has had time to catch up.
Python 3.13 also runs on Amazon Linux 2023, offers better performance, and has support through June 2029. AWS announced Python 3.13 support in Lambda with improvements to the interpreter and reduced memory usage. If you're already testing compatibility, you might as well go to the latest.

Key Breaking Changes to Watch For #

Jumping from Python 3.9 to 3.12 or 3.13 spans several major Python versions. A few things will likely trip you up:
  • Unicode handling in JSON responses changed in Python 3.12. Functions return Unicode characters directly instead of escaped sequences. If downstream consumers parse your Lambda responses, test for this.
  • Removed modules: distutils was removed in Python 3.12. If your function or its dependencies import distutils, they'll break.
  • Container image base: Python 3.12+ uses Amazon Linux 2023 with microdnf as the package manager. If you deploy Lambda functions as container images, update Dockerfiles to use dnf instead of yum.
  • Type hint syntax: Python 3.10+ supports X | Y union types natively. Not a breaking change, but worth knowing if you're updating type hints.
Test your functions locally before deploying. The AWS SAM CLI lets you invoke functions with different runtimes against test events.

How Do I Upgrade Lambda Functions? #

AWS Console (One at a Time) #

Open your function in the Lambda console, go to the "Code" tab, select a new runtime from the dropdown. Good for a handful of functions, doesn't scale beyond that.

AWS CLI (Scriptable) #

aws lambda update-function-configuration \
  --function-name your-function-name \
  --runtime python3.12

Infrastructure as Code (Recommended for Teams) #

Update the runtime in your CloudFormation, CDK, Terraform, or SAM templates and deploy through your normal pipeline. This is the right approach if your functions are already managed through IaC - and if they're not, this migration is a good reason to start.

Track Your Migration Progress #

After you start upgrading, use this query to monitor progress across your accounts. Run it weekly and share with your team:
SELECT
    account_id,
    configuration->>'Runtime' AS runtime,
    COUNT(*) AS function_count,
    ROUND(
        COUNT(*) * 100.0 / SUM(COUNT(*)) OVER (PARTITION BY account_id),
        1
    ) AS percentage
FROM
    aws_lambda_functions
WHERE
    configuration->>'Runtime' LIKE 'python%'
GROUP BY
    account_id, configuration->>'Runtime'
ORDER BY
    account_id, runtime;
This shows you the ratio of Python 3.9 functions to upgraded functions per account - the kind of data your security team or leadership will ask for.

Prevent It from Happening Again with Policies #

Running these queries once finds today's problems. CloudQuery Platform Policies lets you turn any of these queries into a persistent detective control that runs continuously against your infrastructure. Write a policy in SQL that flags any Lambda function running a deprecated runtime, and get notified in Slack, Jira, or via webhook the moment a new violation appears.
Instead of re-running audit queries before each leadership review, a policy like the runtime audit query above catches violations as they happen - whether someone deploys a new function on python3.9 through the console or an IaC template that hasn't been updated yet. Combined with Policy Groups, you can bundle runtime checks alongside your other governance rules into a single enforceable standard.

Key Takeaways: Python 3.9 Lambda Migration #

Security Exposure:
  • Security patches stopped December 15, 2025 - your functions are unpatched now
  • Function updates blocked September 30, 2026 - plan ahead
  • Python 3.8 functions face the same deadlines
Discovery:
  • CloudQuery gives you multi-account, multi-region visibility through SQL
  • The runtime audit query catches all deprecated runtimes, not only Python 3.9
  • The End-of-Life integration automates deprecation tracking across all runtimes and providers
  • Export results to CSV for tracking and reporting
Prioritization:
  • Tag-based filtering surfaces production functions first
  • VPC-attached functions are usually connecting to critical infrastructure
  • Memory allocation and recent modification date serve as rough criticality proxies
  • The combined priority score query ranks functions for migration order
Ongoing Governance:
  • CloudQuery Platform Policies turns these queries into continuous detective controls
  • Get notified automatically when new functions are deployed on deprecated runtimes
  • Bundle runtime checks with other governance rules using Policy Groups
Remediation:
  • Python 3.12 is the stable choice with support through October 2028
  • Python 3.13 has the latest features and support through June 2029
  • Test for distutils removal, Unicode changes, and container image differences before deploying

Start Running These Queries Today #

Your Python 3.9 Lambda functions have been running without security patches for nearly two months. The longer you wait, the wider the exposure window gets. CloudQuery gives you the visibility to find every affected function across all your AWS accounts, prioritize by actual risk, and track your migration progress.
Download CloudQuery to start syncing your Lambda data. Check out the AWS plugin documentation for configuration details, or join our Community to connect with other teams running the same migration. If you're dealing with hundreds of accounts, contact us to see how CloudQuery Platform can help you run these queries across your entire organization.
If you've already upgraded from a previous runtime deprecation, you know the drill. If this is your first one - the queries above will get you from "how many functions do we even have?" to "here's the migration plan" in an afternoon. Don't wait for the update block to force your hand.

Frequently Asked Questions #

What Is the Python 3.9 End-of-Life Date for AWS Lambda? #

AWS ended support for python3.9 in Lambda on December 15, 2025. After this date, the runtime no longer receives security patches or updates and functions lose technical support eligibility.

Will My Lambda Functions Stop Working After the Deprecation? #

No. Your functions continue running on the python3.9 runtime indefinitely. The deprecation affects security patches (stopped December 15, 2025), function creation (blocked August 31, 2026), and function updates (blocked September 30, 2026). Execution is never blocked.

How Can I Find All Python 3.9 Lambda Functions Across Multiple AWS Accounts? #

CloudQuery syncs Lambda function data into a SQL database. Query the aws_lambda_functions table filtering where configuration->>'Runtime' = 'python3.9' to find every affected function across all accounts and regions in a single query.

Should I Upgrade to Python 3.12 or Python 3.13? #

Python 3.12 is the stable choice with Lambda support through October 2028. Python 3.13 offers better performance and support through June 2029. Both run on Amazon Linux 2023. Pick 3.12 for stability or 3.13 if you want the latest features and longest support window.

What Are the Key Breaking Changes Between Python 3.9 and 3.12? #

The most common issues are: distutils module removal (Python 3.12), Unicode handling changes in JSON responses, and container image base changes from Amazon Linux 2 to Amazon Linux 2023 with microdnf. Test your functions with the AWS SAM CLI before deploying to production.

Can I Automate the Runtime Upgrade Across Hundreds of Functions? #

Yes. Use CloudQuery to export affected functions to CSV, then use the AWS CLI, CloudFormation, Terraform, or CDK to batch update runtimes. Start with non-production environments, validate, then roll through production accounts. The migration tracking query in this post shows you progress across accounts over time.

What Happens If I Miss the September 30, 2026 Deadline? #

You won't be able to update function code or configuration. Functions continue running, but you're locked into the current version. To make changes, you'd need to create a new function with a supported runtime and redirect triggers.

Does This Affect Google Cloud Functions or Azure Functions Too? #

Python 3.9 reached community end-of-life on October 5, 2025, which affects all cloud providers. Google Cloud Functions and Azure Functions follow their own deprecation schedules. CloudQuery supports GCP and Azure plugins, so you can run similar queries against those providers' serverless functions.
Ready to find your affected functions? Try CloudQuery and run these queries across your AWS infrastructure today.
Turn cloud chaos into clarity

Find out how CloudQuery can help you get clarity from a chaotic cloud environment with a personalized conversation and demo.