diff --git a/core/core.services.yml b/core/core.services.yml
index 67bebef3113ff1475e0346adde7c56b7d3e23a0b..d587c55d9c780f0fc560f3080ede2fd16cd933c9 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -49,6 +49,11 @@ services:
     arguments: ['@request_stack']
     tags:
       - { name: cache.context }
+  cache_context.protocol_version:
+    class: Drupal\Core\Cache\Context\ProtocolVersionCacheContext
+    arguments: ['@request_stack']
+    tags:
+      - { name: cache.context }
   cache_context.headers:
     class: Drupal\Core\Cache\Context\HeadersCacheContext
     arguments: ['@request_stack']
diff --git a/core/lib/Drupal/Core/Cache/Context/ProtocolVersionCacheContext.php b/core/lib/Drupal/Core/Cache/Context/ProtocolVersionCacheContext.php
new file mode 100644
index 0000000000000000000000000000000000000000..11c20e2f88a7e8f73d4727e208687ded829bbb3e
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/Context/ProtocolVersionCacheContext.php
@@ -0,0 +1,38 @@
+<?php
+
+namespace Drupal\Core\Cache\Context;
+
+use Drupal\Core\Cache\CacheableMetadata;
+
+/**
+ * Defines the ProtocolVersionCacheContext service, for "per protocol" caching.
+ *
+ * Useful to differentiate between HTTP/1.1 and HTTP/2.0 responses for example,
+ * to allow responses to be optimized for protocol-specific characteristics.
+ *
+ * Cache context ID: 'protocol_version'.
+ */
+class ProtocolVersionCacheContext extends RequestStackCacheContextBase implements CacheContextInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getLabel() {
+    return t('Protocol version');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getContext() {
+    return $this->requestStack->getCurrentRequest()->getProtocolVersion();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheableMetadata() {
+    return new CacheableMetadata();
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/Cache/Context/ProtocolVersionCacheContextTest.php b/core/tests/Drupal/Tests/Core/Cache/Context/ProtocolVersionCacheContextTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..530565cfa332d69c3fec865216fb277033c92cf8
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Cache/Context/ProtocolVersionCacheContextTest.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace Drupal\Tests\Core\Cache\Context;
+
+use Drupal\Core\Cache\Context\ProtocolVersionCacheContext;
+use Drupal\Tests\UnitTestCase;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\RequestStack;
+
+/**
+ * @coversDefaultClass \Drupal\Core\Cache\Context\ProtocolVersionCacheContext
+ * @group Cache
+ */
+class ProtocolVersionCacheContextTest extends UnitTestCase {
+
+  /**
+   * @covers ::getContext
+   *
+   * @dataProvider providerTestGetContext
+   */
+  public function testGetContext($protocol, $context) {
+    $request_stack = new RequestStack();
+    $request = Request::create('/');
+    $request->server->set('SERVER_PROTOCOL', $protocol);
+    $request_stack->push($request);
+    $cache_context = new ProtocolVersionCacheContext($request_stack);
+    $this->assertSame($cache_context->getContext(), $context);
+  }
+
+  /**
+   * Provides a list of query arguments and expected cache contexts.
+   */
+  public function providerTestGetContext() {
+    return [
+      ['HTTP/1.0', 'HTTP/1.0'],
+      ['HTTP/1.1', 'HTTP/1.1'],
+      ['HTTP/2.0', 'HTTP/2.0'],
+      ['HTTP/3.0', 'HTTP/3.0'],
+    ];
+  }
+
+}