One of our clients encountered this behaviour when setting Cache-Control in his PHP script: <?php header("Content-Type: text/html; charset=utf-8"); header("Cache-Control: max-age=30, must-revalidate", false); However, server is set to have default expiration of 2 hours for text/html documents: ExpiresActive On ExpiresByType text/html "access plus 120 minutes" This results in these response headers: Cache-Control: max-age=30, must-revalidate Cache-Control: max-age=7200 Expires: Mon, 03 May 2021 16:18:24 GMT This is sort of in accordance with documentation at https://httpd.apache.org/docs/2.4/mod/mod_expires.html which states "When the Expires header is already part of the response generated by the server, for example when generated by a CGI script or proxied from an origin server, this module does not change or add an Expires or Cache-Control header." Indeed, there is no Expires header in response generated by CGI script, but there is a Cache-Control header which gets duplicated (with different value) by mod_expires. I believe such a behaviour is a bug - server should not add its own Cache-Control header if one is already provided by the application. I understand that can result in final response with different expiration times in Expires (added by mod_expires) and Cache-Control max-age (added by the application), but according to RFC 7234 (section 5.3, https://tools.ietf.org/html/rfc7234#section-5.3 ) this should not pose s problem as Cache-Control takes precedence. Obviously, workaround exists in the form of header("Expires: date") Tested with Apache 2.4.38 from Debian Buster and Apache 2.4.46 from Debian Bullseye.