Python 3.10 end of life (31 October 2026): what it means and how to upgrade
Python 3.10 stops getting security fixes in October 2026. Move to Python 3.12 or 3.13; watch for removed modules, distutils and old packages.
If your application, API, worker or data pipeline runs on Python 3.10, security support ends in October 2026. Python's developer guide lists the end of life as 2026-10, and endoflife.date gives 31 October 2026. "End of life" means the Python team stops releasing new 3.10 versions, so security holes found after that date are not fixed in official Python 3.10 releases. This affects Django, Flask and FastAPI apps, Celery workers, scripts and scheduled jobs alike.
What changes on the date (and what doesn't)
Python 3.10 has had source-only security releases since its last bugfix release in April 2023 (PEP 619). In October 2026 even those stop.
What does not change:
- Your servers and containers keep running. Nothing is switched off.
- Some distributions and vendors keep patching their own Python builds. Ubuntu 22.04 LTS ships Python 3.10 as its system Python, and Canonical backports security fixes to it for the life of that release (longer with Ubuntu Pro/ESM). Red Hat and other enterprise distributions do the same for the versions they ship, and vendors such as HeroDevs sell extended support. These options exist; whether they cover you depends on where your Python comes from.
What does change:
- The official
python:3.10Docker images and python.org builds stop getting updates. - Libraries drop Python 3.10 support over time. New releases of your dependencies may require 3.11 or 3.12, which leaves you on old, unpatched versions of those libraries too.
- Security scanners and compliance reviews flag the unsupported runtime.
Which versions to move to
| Version | Security support until | Notes |
|---|---|---|
| Python 3.10 | Oct 2026 (31 Oct per endoflife.date) | Ends this year |
| Python 3.11 | Oct 2027 | Buys one year |
| Python 3.12 | Oct 2028 | Good default target |
| Python 3.13 | Oct 2029 | Good target if your packages support it |
| Python 3.14 | Oct 2030 | Newest; check package support first |
Source: Python developer guide, status of Python versions, cross-checked with endoflife.date/python.
I usually recommend Python 3.12 or 3.13. Most maintained packages ship wheels for both, and either gives you two to three years before the next move. Python 3.11 is the smallest jump, but you'd be doing this again in 2027.
How to check what you run
Check each place Python runs: servers, containers, CI, serverless functions and developer machines. They often differ.
# The interpreter on the server or in the container
python --version
python3 --version
# Inside a virtualenv, confirm which interpreter it was built from
.venv/bin/python --version
# What your project declares
grep -n "requires-python" pyproject.toml # e.g. requires-python = ">=3.10"
grep -n "python_requires" setup.cfg setup.py 2>/dev/null
cat .python-version runtime.txt 2>/dev/null
# Docker base image
grep -i '^FROM' Dockerfile # e.g. FROM python:3.10-slim
# CI images and matrices
grep -rn "python-version\|python:3" .github/ .gitlab-ci.yml 2>/dev/null
For a quick check without running anything, paste your pyproject.toml or Dockerfile into the free stack health check. It runs in your browser and shows which runtimes and frameworks are past or near end of life.
Upgrade checklist
- Inventory. List every app, worker, cron job, Lambda or Cloud Function, and CI pipeline that runs Python, with its version and where the interpreter comes from (system package, Docker image, pyenv, uv).
- Tests first. Get the test suite green on 3.10. If coverage is thin, add tests for the flows that matter most: sign-in, payments, imports, the main API endpoints.
- Show warnings. Run the tests with
python -W default -m pytest(or-W error::DeprecationWarningto make them fail). Warnings on 3.10 point at code that breaks later. - Fix removals and deprecations for your target version:
- Python 3.11 (What's New):
asyncio.coroutineis removed; useasync def. Thebinhexmodule is removed. - Python 3.12 (What's New):
distutils,imp,asynchat,asyncoreandsmtpdare removed; unittest aliases such asassertEqualsare removed;configparser.SafeConfigParseris removed;venvno longer pre-installs setuptools; invalid escape sequences like"\d"now raiseSyntaxWarning;datetime.utcnow()is deprecated in favor ofdatetime.now(datetime.UTC). - Python 3.13 (What's New): 19 old modules are removed, including
cgi,cgitb,crypt,imghdr,pipes,telnetlib,nntplibandaudioop;lib2to3and2to3are removed;locals()in functions now returns an independent snapshot (PEP 667).
- Python 3.11 (What's New):
- Update dependencies. Upgrade your pins (
requirements.txt,poetry.lock,uv.lock) to versions that support the target Python. Watch packages with compiled parts (NumPy, pandas, psycopg2, lxml, cryptography): old versions have no wheels for new Python versions and try to build from source, which often fails in slim images. - Framework notes. Check the Django FAQ table: Django 5.2 LTS supports Python 3.10 to 3.14, while Django 6.0 and 6.1 need Python 3.12 or newer. Current FastAPI releases require Python 3.10 or newer (PyPI), so FastAPI itself runs fine on 3.12 and 3.13; upgrade FastAPI and Pydantic together if you're on old versions.
- Update
requires-python, the Dockerfile and CI. Run the CI matrix on 3.10 and the target version until the switch, then drop 3.10. - Staging. Deploy to staging with the same image and settings as production. Test background workers, scheduled jobs, file handling and outbound integrations, not just the web pages.
- Deploy with a rollback. Ship a new image or a new server, keep the old one ready, and watch logs and error tracking for a few days.
Common breakages
ModuleNotFoundError: No module named 'distutils'on 3.12, usually from an old package'ssetup.pyor code that useddistutils.util.strtobool. Upgrade the package or replace the call.ModuleNotFoundError: No module named 'imp'from old plugins or vendored code. Useimportlib.ModuleNotFoundError: No module named 'cgi'on 3.13, often from old web or email-parsing code. The same happens withimghdr,pipesandtelnetlib.AttributeError: ... has no attribute 'assertEquals'in test suites on 3.12. Rename toassertEqualand the other modern names.- Failed installs because a pinned version of a compiled package has no wheel for the new Python and the build tools aren't in the image.
SyntaxWarning: invalid escape sequenceflooding logs from regex strings. Use raw strings (r"\d+").- Timezone bugs when replacing
utcnow()without care:datetime.now(datetime.UTC)returns an aware datetime, and comparing it with naive values raisesTypeError.
Cost and timeline
The honest answer is that it depends on test coverage and on how far behind your dependencies are. A FastAPI or Django app with tests and maintained packages can move from 3.10 to 3.12 in a few days. An app with no tests, old pins, and code that uses removed modules takes longer, because each of those needs a fix and a check.
Start before October so you have time for staging and for waiting on a library release if you need one.
I do this as a fixed-price service: the End-of-Life Runtime Upgrade starts from $390 for one runtime. If you're not sure how much work is hidden in the code, a codebase assessment gives you a written answer before you commit.
If Python 3.10 is in your stack, send me your versions and I'll tell you what the move involves.
Questions
When does Python 3.10 reach end of life?
In October 2026. Python's developer guide lists end of life as 2026-10, and endoflife.date gives 31 October 2026. After that, the Python team releases no more 3.10 versions, including security fixes.
Will my Python 3.10 app stop working after October 2026?
No. The interpreter keeps running. The risk is that security holes found later are not fixed in official Python 3.10 releases, and new versions of your libraries stop supporting 3.10.
Which Python version should I upgrade to?
Python 3.12 or 3.13 for most production apps. Python 3.12 is supported until October 2028 and 3.13 until October 2029. Python 3.11 only buys one year.
Does Django still support Python 3.10?
Django 5.2 LTS supports Python 3.10 to 3.14. Django 6.0 and 6.1 require Python 3.12 or newer, so upgrading Python is also what unlocks newer Django.
What breaks when moving from Python 3.10 to 3.12 or 3.13?
Most often: code or packages that import distutils, imp, asyncore or smtpd (removed in 3.12), the old stdlib modules such as cgi, telnetlib and imghdr (removed in 3.13), unittest aliases like assertEquals, and pinned packages with no wheels for the new version.
How long does a Python 3.10 upgrade take?
It depends on test coverage and how many dependencies are pinned to old versions. A tested app with maintained packages can move in days; an untested one with old pins can take a few weeks.
Written by MD Morsalin, contract software engineer. Published September 26, 2026.