Join our Newsletter — 33% off our NHI Course
Home› Guides› Python End of Life Versions: Dates, Detection and…
Guide Vulnerability Management

Python End of Life Versions: Dates, Detection and Upgrade Planning

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 14 November 2026 15 min read
On this page

Every CPython branch stops receiving fixes five years after its first release, and from that day any vulnerability found in it stays open for good. Python 3.9 reached end of life on 31 October 2025 and Python 3.10 on 1 October 2026, yet both are still common in container base images, serverless functions, CI runners and Linux distributions. This guide gives the official Python dates and lifecycle phases, explains how platform and distribution schedules differ from upstream, and shows how to find old interpreters across hosts, containers and serverless platforms, then how to plan, test and roll back the upgrade. It is for platform, application security and vulnerability management teams. For the cross-language view see the End-of-Life Language Runtimes guide; this page goes deeper on Python only.

This is an independent guide from NHI Mgmt Group, based on the Python project's public documentation as of November 2026. It is not sponsored or reviewed by the Python Software Foundation. Release dates can change, so confirm them against the project's current status page.

Key takeaways

  • Python 3.11 to 3.15 are the supported branches. As checked on 13 November 2026, 3.14 and 3.15 are in bugfix, 3.11, 3.12 and 3.13 are security-only, and 3.10 and older are end of life.
  • Security-only is not the same as fully supported. In the security phase the project issues source-only releases as needed and no new binary installers, so Windows and macOS users of those branches depend on other packagers.
  • Three clocks apply, not one. Upstream CPython, your serverless platform and your Linux distribution each publish separate dates; a distribution can keep patching a branch after upstream stops, while a platform can block updates on its own timetable.
  • Interpreters hide in many places. Pinned base images, virtual environments, CI setup steps, bundled vendor software and old function runtimes all keep an old interpreter alive after the application code has moved on.
  • Removed modules are the classic blocker. distutils, asyncore, asynchat and imp went in 3.12, and 19 more legacy modules such as cgi, crypt and telnetlib went in 3.13, so jumps from 3.9 or 3.10 often fail on imports first.

How the Python lifecycle works

CPython has released a new feature version every October since 3.9, under PEP 602 "Annual Release Cycle for Python" (status: Active, process PEP). Each branch moves through phases described in the Python Developer's Guide:

PhaseWhat is acceptedReleasesDuration
FeatureNew features, bug fixes and security fixesAlphasUntil the first beta
PrereleaseFixes to new features, bug and security fixes; no new featuresBetas and release candidatesUntil the .0 release
BugfixBug and security fixesFull releases with binary installers roughly every two monthsTwo years from release (18 months for branches before 3.13)
SecuritySecurity fixes onlySource-only releases as needed; no new binariesFrom the end of bugfix until five years after release
End-of-lifeNothing; the branch is frozenNonePermanent

Two consequences matter for planning. First, the support period is predictable: a branch released in October of year N ends in October of year N+5. Second, the move from 18 to 24 months of bugfix support started with 3.13, so 3.11 and 3.12 spent longer in security-only mode than newer branches will. Teams that install Python from python.org binaries on Windows or macOS should treat entry to the security phase as the practical upgrade trigger, because no further installers are built for that branch.

Official dates and current status

Dates below are from the Python Developer's Guide "Status of Python versions" page, checked on 13 November 2026. The project marks scheduled end of life dates as subject to change.

BranchSchedule PEPFirst releaseEnd of lifeStatus on 13 Nov 2026
2.7PEP 3732010-07-032020-01-01EOL
3.6PEP 4942016-12-232021-12-23EOL
3.7PEP 5372018-06-272023-06-27EOL
3.8PEP 5692019-10-142024-10-07EOL
3.9PEP 5962020-10-052025-10-31EOL
3.10PEP 6192021-10-042026-10-01EOL
3.11PEP 6642022-10-24October 2027 (scheduled)Security
3.12PEP 6932023-10-02October 2028 (scheduled)Security
3.13PEP 7192024-10-07October 2029 (scheduled)Security
3.14PEP 7452025-10-07October 2030 (scheduled)Bugfix
3.15PEP 790October 2026October 2031 (scheduled)Bugfix
3.16 (main)PEP 8262027-10-06 (scheduled)October 2032 (scheduled)Feature development

Practical reading: anything on 3.10 or older is unsupported upstream today, and 3.11 has under a year left. A team starting an upgrade from 3.9 or 3.10 now should target 3.13 or newer rather than 3.11, to avoid a second migration within twelve months.

Platform and distribution clocks

Managed platforms and Linux distributions publish their own Python schedules. They do not change the upstream date, but they decide when you are blocked and who supplies patches. Platforms are listed alphabetically.

PlatformPython dates (as published, checked 13 Nov 2026)What happens at end of support
AWS Lambdapython3.10 deprecated 31 Oct 2026; python3.9 deprecated 15 Dec 2025; both block create 29 Jul 2027 and block update 31 Aug 2027. python3.11 deprecates 30 Jun 2027; python3.12 31 Oct 2028; python3.13 and python3.14 30 Jun 2029At least 180 days' email notice to the account's primary contact; on deprecation AWS may stop applying security updates; functions keep running indefinitely; rolling back to a deprecated runtime may be blocked after the update block
Azure FunctionsPython 3.11 expected end of support October 2027, 3.12 October 2028; the Linux Consumption plan supports up to 3.12 and retires on 30 September 2028, with Flex Consumption as the documented destinationSupport ends on the earlier of the community end date and the base OS end date; apps keep running but receive no security patches, may be limited in scaling, and must upgrade before Microsoft provides support
Google Cloud Run functionspython310 deprecated 4 Oct 2026, decommission 4 Apr 2027; python39 decommissioned 5 Apr 2026; python311 deprecates 24 Oct 2027Notice 90 days before deprecation; after decommission you cannot create or update functions on the runtime and existing functions may be disabled
Red Hat Enterprise LinuxPython 3.9 is a Full Life stream on RHEL 9 and Python 3.12 on RHEL 10, lasting as long as the RHEL release; Application Streams have their own dates, for example Python 3.11 on RHEL 8 and 9 retired May 2026, Python 3.12 on RHEL 9 retires April 2027Fixes come from Red Hat backports, not upstream releases, so the version string stays old while patches continue

For Lambda migration mechanics, see the AWS Lambda Runtime Deprecation guide; for Ubuntu's handling of its bundled Python, see Ubuntu LTS End of Standard Support. The distribution case is the most common source of false positives: a scanner that flags "Python 3.9 is EOL" on a RHEL 9 host is right about upstream but wrong about patch availability. Record the supplier of fixes for each interpreter, not only its version.

Finding Python versions across hosts, containers and serverless

Combine what code declares with what actually runs. Declared versions show intent; observed versions show exposure.

  1. Read declarations in every repository. Collect requires-python in pyproject.toml, python_requires in setup.py or setup.cfg, .python-version files used by version managers, tox and nox environment lists, the python-version input in CI setup steps, and every FROM python: line in Dockerfiles. The Python Packaging User Guide notes that the Programming Language :: Python :: 3.x classifiers are only for search and browsing on PyPI; installers enforce requires-python, not classifiers.
  2. Read container image metadata. The official python images set a PYTHON_VERSION environment variable, which can be read from image configuration without running the container. For custom or distroless images, generate an SBOM and look for the interpreter package. Inventory images running in each cluster, not just the registry. See the Container Image Vulnerability Management Guide and the SBOM Guide.
  3. Watch floating tags. In the official images, latest, 3, slim and alpine point to the newest release (3.15 as of November 2026), so a rebuild can change the major version without a code change. The reverse also happens: python:3.9-slim keeps rebuilding cleanly on an EOL branch for years. Pin the minor version on purpose and change it on purpose.
  4. Look for version fingerprints in artefacts. Bytecode caches name the interpreter (module.cpython-39.pyc), compiled wheels carry an ABI tag such as cp310, and a virtual environment's pyvenv.cfg records the base interpreter it was created from. These reveal old runtimes inside packaged applications and vendor bundles where no Dockerfile exists.
  5. Query hosts. Use endpoint or configuration management inventory to report every interpreter installed (system packages, version managers, conda environments, side-by-side installs on Windows) and which one each service unit, scheduled task or cron job executes. At runtime, sys.version_info and platform.python_version() give the exact version, which applications can report to telemetry.
  6. List serverless runtimes. Export the runtime identifier of every function across all accounts, subscriptions, projects and regions: Lambda python3.x, Cloud Run functions python3xx, and the Python version shown in each Azure function app's configuration. Compare against the platform tables above.
  7. Ask vendors. Appliances, data tools and agents often bundle their own interpreter. Get the version and the vendor's upgrade date in writing and record it in the asset register. See the CIS Control 2 Inventory and Control of Software Assets Guide.

Where identity fits: every old function, image and runner found here also holds credentials: an execution role, a service account, a PyPI upload token or cloud keys. Old build images are a known leak path: in the PyPI Admin GitHub Token Leak 2024, compiled .pyc files carrying an admin token sat in public images for about 15 months. When you retire an EOL image or runner, rotate what it held and move publishing to short-lived credentials. See the PyPI API Tokens and Trusted Publishing Security Guide and the NHI Discovery Across Cloud, SaaS, CI/CD and On-Premises Environments guide.

Upgrade planning and decision guidance

OptionWhen it fitsTrade-off
Upgrade to 3.14 (EOL October 2030)Maintained services with good test coverage and current dependenciesLargest jump from 3.9 or 3.10; longest runway; still in bugfix with binary releases
Upgrade to 3.13 (EOL October 2029)Large codebases where some dependencies are not yet tested on 3.14Smaller change; already security-only, so no new binaries from python.org
Upgrade to 3.12 or 3.11Only where a hard dependency or platform plan blocks newer versionsAnother migration due within one or two years; 3.11 ends October 2027
Stay on a distribution-supported branchHost software using the OS interpreter, such as RHEL 9 with Python 3.9Patched by the distribution for the OS lifetime; keep application code off the system interpreter where possible
Retire or isolateAbandoned functions, unused scripts, vendor software with no upgrade pathNeeds an owner decision; isolation reduces exposure but does not remove it

Decision rule: production should run a branch with at least 12 months of upstream support remaining, or a distribution-patched interpreter with a recorded supplier. Small teams should jump straight to the newest bugfix branch to cut the number of migrations. Large organisations should upgrade shared base images, CI templates and internal libraries first, because one change there moves many services, then give teams dated targets.

Common blockers and how to handle them:

  • Removed standard library modules: 3.12 removed distutils (PEP 632), asynchat, asyncore and imp; 3.13 completed PEP 594 by removing 19 further modules including cgi, cgitb, crypt, nntplib, pipes, telnetlib and uu. Search the codebase and dependencies for these imports before anything else. Setuptools still provides a distutils shim for build code that needs it.
  • Changed environment defaults: from 3.12, virtual environments created with venv no longer pre-install setuptools, so scripts that assume pkg_resources or setup.py tooling is present fail. Declare build dependencies explicitly.
  • Compiled extensions: packages with C extensions need wheels built for the new ABI tag. Check that every compiled dependency publishes wheels for the target version, and plan replacements for abandoned ones.
  • Frozen dependency trees: projects stuck on an old interpreter are usually stuck on old library versions too, so the runtime upgrade and the dependency upgrade are one project. See the Dependency Update Automation Guide and the Python Dependency Supply Chain Guide.
  • Upper bounds on requires-python: the packaging guide advises thinking twice before setting an upper bound, because it can block installs on newer interpreters for reasons unrelated to compatibility.

Testing and rollback

  1. Upgrade dependencies first. Move libraries to versions that support both the current and target interpreter, deploy, and only then switch the runtime. Two small changes are safer than one large one.
  2. Add the target version to the CI matrix. Run the full test suite on both versions with warnings enabled (python -W error::DeprecationWarning in CI) so deprecations fail builds before they become removals.
  3. Rebuild, do not patch in place. Build new images and function packages from a pinned base, regenerate the SBOM and rescan before deployment. Rebuild virtual environments rather than copying them, since they are tied to the interpreter that created them.
  4. Roll out in rings. Non-production, then a canary slice of production or one function alias, comparing error rate, latency and memory against the old version, then the rest.
  5. Keep a rollback artefact. Retain the previous image digest or function version for a fixed window. On Lambda, AWS warns that rolling back to a deprecated runtime may be blocked once the update block date passes, so finish before 31 August 2027 for 3.9 and 3.10 functions.
  6. Close the loop. Delete old images, interpreters and virtual environments after the window, and record any remaining instance as a dated exception.

Risks, detection and measurement

  • Permanent known vulnerabilities: once a branch is frozen, flaws fixed in supported branches stay open in it. Internet-facing services become candidates for MITRE ATT&CK T1190 Exploit Public-Facing Application.
  • Supply chain drag: libraries drop old interpreters, so fixes in dependencies become unreachable, raising exposure to T1195.001 Compromise Software Dependencies and Development Tools. See the Python Packaging and pip Security Guide.
  • Platform cut-offs: a function that cannot be updated after a block date cannot even receive a configuration fix during an incident.
  • Audit findings: unsupported components are an explicit control requirement (NIST SP 800-53 SA-22).
FrameworkReferenceHow it applies to Python EOL
NIST CSF 2.0ID.AM-02, ID.RA-01, PR.PS-02Inventory interpreters, record EOL branches as vulnerabilities, replace software by risk
NIST SP 800-53 Rev 5CM-8, SA-22, SI-2, RA-5Component inventory, unsupported components, flaw remediation, scanning that reports interpreter versions
CIS Controls v8.12.2 Ensure Authorized Software is Currently SupportedEOL interpreters flagged with a documented exception or removed
ISO/IEC 27001:2022 Annex A8.8 Management of technical vulnerabilitiesEOL runtimes treated as a vulnerability with an owner and deadline

Metrics that show progress: percentage of production workloads on a branch with at least 12 months of upstream support; count of images, functions and hosts on 3.10 or older, trending to zero; functions on deprecated platform runtimes, target zero before block dates; number and age of open SA-22 exceptions, split into distribution-patched and unpatched; percentage of repositories with an explicit, supported requires-python and pinned base image.

Common failure patterns

  • Scanning code, not runtimes: dependency scanners report libraries but miss the interpreter in the base image or the function runtime setting.
  • Treating every "3.9" alike: a RHEL 9 system interpreter with vendor backports and a python:3.9-slim image with no further upstream releases need different responses.
  • Unwatched notification contacts: platform deprecation emails go to account primary contacts nobody reads, so the first warning is a failed deployment.
  • Upgrading to the next branch only: moving 3.10 to 3.11 in late 2026 buys under a year before the next migration.
  • Leaving old artefacts in registries: superseded images and function versions stay deployable and keep the credentials baked into them.

Practitioner checklist

  • Record upstream EOL dates for every Python branch in use, with the date you checked the devguide status page.
  • Record the platform or distribution date and the fix supplier for every interpreter found.
  • Scan repositories for requires-python, .python-version, CI Python settings and FROM python: lines.
  • Read PYTHON_VERSION or SBOM data for every running image, and pin minor versions deliberately.
  • Export Python runtime identifiers for every function across all accounts and regions.
  • Move 3.10 and older to 3.13 or 3.14; plan 3.11 exits before October 2027.
  • Search code and dependencies for modules removed in 3.12 and 3.13 before switching.
  • Run CI on the target version with deprecation warnings as errors before cutover.
  • Rotate credentials held by retired images, runners and functions.
  • Track vendor-bundled interpreters with written vendor dates and dated SA-22 exceptions.

Standards and references

Related NHI Mgmt Group resources: End-of-Life Language Runtimes · Node.js End of Life Versions · Unsupported PHP versions · Python Security Guide · AWS Lambda Runtime Deprecation

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 14 November 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org