Changelog - 2026¶
25.1.0 - 2026-02-13¶
New Features¶
- Control Interface (gunicornc): Add interactive control interface for managing running Gunicorn instances, similar to birdc for BIRD routing daemon (PR #3505)
- Unix socket-based communication with JSON protocol
- Interactive mode with readline support and command history
- Commands:
show all/workers/dirty/config/stats/listeners - Worker management:
worker add/remove/kill,dirty add/remove - Server control:
reload,reopen,shutdown - New settings:
--control-socket,--control-socket-mode,--no-control-socket - New CLI tool:
gunicorncfor connecting to control socket -
See Control Interface Guide for details
-
Dirty Stash: Add global shared state between workers via
dirty.stash(PR #3503) - In-memory key-value store accessible by all workers
- Supports get, set, delete, clear, keys, and has operations
-
Useful for sharing state like feature flags, rate limits, or cached data
-
Dirty Binary Protocol: Implement efficient binary protocol for dirty arbiter IPC using TLV (Type-Length-Value) encoding (PR #3500)
- More efficient than JSON for binary data
- Supports all Python types: str, bytes, int, float, bool, None, list, dict
-
Better performance for large payloads
-
Dirty TTIN/TTOU Signals: Add dynamic worker scaling for dirty arbiters (PR #3504)
- Send SIGTTIN to increase dirty workers
- Send SIGTTOU to decrease dirty workers
- Respects minimum worker constraints from app configurations
Changes¶
- ASGI Worker: Promoted from beta to stable
- Dirty Arbiters: Now marked as beta feature
Documentation¶
- Fix Markdown formatting in /configure documentation
25.0.3 - 2026-02-07¶
Bug Fixes¶
-
Fix RuntimeError when StopIteration is raised inside ASGI response body coroutine (PEP 479 compliance)
-
Fix deprecation warning for passing maxsplit as positional argument in
re.split()(Python 3.13+)
25.0.2 - 2026-02-06¶
Bug Fixes¶
-
Fix ASGI concurrent request failures through nginx proxy by normalizing sockaddr tuples to handle both 2-tuple (IPv4) and 4-tuple (IPv6) formats (PR #3485)
-
Fix graceful disconnect handling for ASGI worker to properly handle client disconnects without raising exceptions (PR #3485)
-
Fix lazy import of dirty module for gevent compatibility - prevents import errors when concurrent.futures is imported before gevent monkey-patching (PR #3483)
Changes¶
-
Refactor: Extract
_normalize_sockaddrutility function for consistent socket address handling across workers -
Add license headers to all Python source files
-
Update copyright year to 2026 in LICENSE and NOTICE files
25.0.1 - 2026-02-02¶
Bug Fixes¶
- Fix ASGI streaming responses (SSE) hanging: add chunked transfer encoding for HTTP/1.1 responses without Content-Length header. Without chunked encoding, clients wait for connection close to determine end-of-response.
Changes¶
- Update celery_alternative example to use FastAPI with native ASGI worker and uvloop for async task execution
Testing¶
- Add ASGI compliance test suite with Docker-based integration tests covering HTTP, WebSocket, streaming, lifespan, framework integration (Starlette, FastAPI), HTTP/2, and concurrency scenarios
25.0.0 - 2026-02-01¶
New Features¶
- Dirty Arbiters: Separate process pool for executing long-running, blocking operations (AI model loading, heavy computation) without blocking HTTP workers (PR #3460)
- Inspired by Erlang's dirty schedulers
- Asyncio-based with Unix socket IPC
- Stateful workers that persist loaded resources
- New settings:
--dirty-app,--dirty-workers,--dirty-timeout,--dirty-threads,--dirty-graceful-timeout -
Lifecycle hooks:
on_dirty_starting,dirty_post_fork,dirty_worker_init,dirty_worker_exit -
Per-App Worker Allocation for Dirty Arbiters: Control how many dirty workers load each app for memory optimization with heavy models (PR #3473)
- Set
workersclass attribute on DirtyApp (e.g.,workers = 2) - Or use config format
module:class:N(e.g.,myapp:HeavyModel:2) - Requests automatically routed to workers with the target app
- New exception
DirtyNoWorkersAvailableErrorfor graceful error handling -
Example: 8 workers × 10GB model = 80GB → with
workers=2: 20GB (75% savings) -
HTTP/2 Support (Beta): Native HTTP/2 (RFC 7540) support for improved performance with modern clients (PR #3468)
- Multiplexed streams over a single connection
- Header compression (HPACK)
- Flow control and stream prioritization
- Works with gthread, gevent, and ASGI workers
- New settings:
--http-protocols,--http2-max-concurrent-streams,--http2-initial-window-size,--http2-max-frame-size,--http2-max-header-list-size - Requires SSL/TLS and h2 library:
pip install gunicorn[http2] - See HTTP/2 Guide for details
-
New example:
examples/http2_gevent/with Docker and tests -
HTTP 103 Early Hints: Support for RFC 8297 Early Hints to enable browsers to preload resources before the final response (PR #3468)
- WSGI:
environ['wsgi.early_hints'](headers)callback - ASGI:
http.response.informationalmessage type -
Works with both HTTP/1.1 and HTTP/2
-
uWSGI Protocol for ASGI Worker: The ASGI worker now supports receiving requests via the uWSGI binary protocol from nginx (PR #3467)
Bug Fixes¶
-
Fix HTTP/2 ALPN negotiation for gevent and eventlet workers when
do_handshake_on_connectis False (the default). The TLS handshake is now explicitly performed before checkingselected_alpn_protocol(). -
Fix setproctitle initialization with systemd socket activation (#3465)
-
Fix
Expect: 100-continuehandling: ignore the header for HTTP/1.0 requests since 100-continue is only valid for HTTP/1.1+ (PR #3463) -
Fix missing
_expected_100_continueattribute in UWSGIRequest -
Disable setproctitle on macOS to prevent segfaults during process title updates
-
Publish full exception traceback when the application fails to load (#3462)
Deprecations¶
- Eventlet Worker: The
eventletworker is deprecated and will be removed in Gunicorn 26.0. Eventlet itself is no longer actively maintained. Please migrate togevent,gthread, or another supported worker type.
Changes¶
- Remove obsolete Makefile targets (PR #3471)
24.1.1 - 2026-01-24¶
Bug Fixes¶
- Fix
forwarded_allow_ipsandproxy_allow_ipsto remain as strings for backward compatibility with external tools like uvicorn. Network validation now uses strict mode to detect invalid CIDR notation (e.g.,192.168.1.1/24where host bits are set) (#3458, PR #3459)
24.1.0 - 2026-01-23¶
New Features¶
- Official Docker Image: Gunicorn now publishes official Docker images to GitHub
Container Registry at
ghcr.io/benoitc/gunicorn - Based on Python 3.12 slim image
- Uses recommended worker formula (2 × CPU + 1)
-
Configurable via environment variables
-
PROXY Protocol v2 Support: Extended PROXY protocol implementation to support the binary v2 format in addition to the existing text-based v1 format (PR #3451)
- New
--proxy-protocolmodes:off,v1,v2,auto automode (default when enabled) detects v1 or v2 automatically- v2 binary format is more efficient and supports additional metadata
-
Works with HAProxy, AWS NLB/ALB, and other PROXY protocol v2 sources
-
CIDR Network Support:
--forwarded-allow-ipsand--proxy-allow-fromnow accept CIDR notation (e.g.,192.168.0.0/16) for specifying trusted networks (PR #3449) -
Socket Backlog Metric: New
gunicorn.socket.backloggauge metric reports the current socket backlog size on Linux systems (PR #3450) -
InotifyReloader Enhancement: The inotify-based reloader now watches newly imported modules, not just those loaded at startup (PR #3447)
Bug Fixes¶
-
Fix signal handling regression where SIGCLD alias caused "Unhandled signal: cld" errors on Linux when workers fail during boot (#3453)
-
Fix socket blocking mode on keepalive connections preventing SSL handshake failures with async workers (PR #3452)
-
Use smaller buffer size in
finish_body()for faster timeout detection on slow or abandoned connections (PR #3453) -
Handle
SSLWantReadErrorinfinish_body()to prevent worker hangs during SSL renegotiation (PR #3448) -
Log SIGTERM as info level instead of warning to reduce noise in orchestrated environments (PR #3446)
-
Print exception details to stderr when worker fails to boot (PR #3443)
-
Fix
unreader.unread()to prepend data to buffer instead of appending (PR #3442) -
Prevent
RecursionErrorwhen pickling Config objects (PR #3441) -
Use proper exception chaining with
raise fromin glogging.py (PR #3440)
24.0.0 - 2026-01-23¶
New Features¶
- ASGI Worker (Beta): Native asyncio-based ASGI support for running async Python frameworks like FastAPI, Starlette, and Quart without external dependencies (PR #3444)
- HTTP/1.1 with keepalive connections
- WebSocket support
- Lifespan protocol for startup/shutdown hooks
- Optional uvloop for improved performance
-
New settings:
--asgi-loop,--asgi-lifespan,--root-path -
uWSGI Binary Protocol: Support for receiving requests from nginx via
uwsgi_passdirective, enabling efficient binary protocol communication (PR #3444) -
New settings:
--protocol uwsgi,--uwsgi-allow-from -
Documentation Migration: Migrated documentation from Sphinx to MkDocs with Material theme for improved navigation and mobile experience (PR #3426)
Security¶
-
eventlet: Require eventlet >= 0.40.3 to address CVE-2021-21419 (websocket memory exhaustion) and CVE-2025-58068 (HTTP request smuggling) (PR #3445)
-
gevent: Require gevent >= 24.10.1 to address CVE-2023-41419 (HTTP request smuggling) and CVE-2024-3219 (socket.socketpair vulnerability) (PR #3445)
-
tornado: Require tornado >= 6.5.0 to address CVE-2025-47287 (HTTP request smuggling) and other security fixes (PR #3445)
Changes¶
- Documentation now hosted at https://gunicorn.org
- Updated license configuration to PEP 639 format for uv compatibility
ASGI Worker Beta
The ASGI worker is a beta feature. While tested, the API and behavior may change in future releases. Please report any issues on GitHub.