diff --git a/core/lib/Drupal/Core/Database/FetchModeTrait.php b/core/lib/Drupal/Core/Database/FetchModeTrait.php
index d74f0ef8f128b82e1687554182e58ccb3a34218c..b9e0018d519b3d68b42a6c9f8fd2c2d71830a38f 100644
--- a/core/lib/Drupal/Core/Database/FetchModeTrait.php
+++ b/core/lib/Drupal/Core/Database/FetchModeTrait.php
@@ -7,6 +7,41 @@
  */
 trait FetchModeTrait {
 
+  /**
+   * Map FETCH_* modes to their literal for inclusion in messages.
+   *
+   * @see https://github.com/php/php-src/blob/master/ext/pdo/php_pdo_driver.h#L65-L80
+   */
+  protected array $fetchModeLiterals = [
+    \PDO::FETCH_DEFAULT => 'FETCH_DEFAULT',
+    \PDO::FETCH_LAZY => 'FETCH_LAZY',
+    \PDO::FETCH_ASSOC => 'FETCH_ASSOC',
+    \PDO::FETCH_NUM => 'FETCH_NUM',
+    \PDO::FETCH_BOTH => 'FETCH_BOTH',
+    \PDO::FETCH_OBJ => 'FETCH_OBJ',
+    \PDO::FETCH_BOUND => 'FETCH_BOUND',
+    \PDO::FETCH_COLUMN => 'FETCH_COLUMN',
+    \PDO::FETCH_CLASS => 'FETCH_CLASS',
+    \PDO::FETCH_INTO => 'FETCH_INTO',
+    \PDO::FETCH_FUNC => 'FETCH_FUNC',
+    \PDO::FETCH_NAMED => 'FETCH_NAMED',
+    \PDO::FETCH_KEY_PAIR => 'FETCH_KEY_PAIR',
+    \PDO::FETCH_CLASS | \PDO::FETCH_CLASSTYPE => 'FETCH_CLASS | FETCH_CLASSTYPE',
+    \PDO::FETCH_CLASS | \PDO::FETCH_PROPS_LATE => 'FETCH_CLASS | FETCH_PROPS_LATE',
+  ];
+
+  /**
+   * The fetch modes supported.
+   */
+  protected array $supportedFetchModes = [
+    \PDO::FETCH_ASSOC,
+    \PDO::FETCH_CLASS,
+    \PDO::FETCH_CLASS | \PDO::FETCH_PROPS_LATE,
+    \PDO::FETCH_COLUMN,
+    \PDO::FETCH_NUM,
+    \PDO::FETCH_OBJ,
+  ];
+
   /**
    * Converts a row of data in FETCH_ASSOC format to FETCH_BOTH.
    *
@@ -15,8 +50,14 @@ trait FetchModeTrait {
    *
    * @return array
    *   The row in FETCH_BOTH format.
+   *
+   * @deprecated in drupal:10.2.0 and is removed from drupal:11.0.0. Use
+   *   supported modes only.
+   *
+   * @see https://www.drupal.org/node/3377999
    */
   protected function assocToBoth(array $rowAssoc): array {
+    @trigger_error(__METHOD__ . '() is deprecated in drupal:10.2.0 and is removed from drupal:11.0.0. Use supported modes only. See https://www.drupal.org/node/3377999', E_USER_DEPRECATED);
     // \PDO::FETCH_BOTH returns an array indexed by both the column name
     // and the column number.
     return $rowAssoc + array_values($rowAssoc);
@@ -79,8 +120,14 @@ protected function assocToClass(array $rowAssoc, string $className, array $const
    *
    * @return object
    *   The row in FETCH_CLASS format.
+   *
+   * @deprecated in drupal:10.2.0 and is removed from drupal:11.0.0. Use
+   *   supported modes only.
+   *
+   * @see https://www.drupal.org/node/3377999
    */
   protected function assocToClassType(array $rowAssoc, array $constructorArguments): object {
+    @trigger_error(__METHOD__ . '() is deprecated in drupal:10.2.0 and is removed from drupal:11.0.0. Use supported modes only. See https://www.drupal.org/node/3377999', E_USER_DEPRECATED);
     $className = array_shift($rowAssoc);
     return $this->assocToClass($rowAssoc, $className, $constructorArguments);
   }
@@ -95,8 +142,14 @@ protected function assocToClassType(array $rowAssoc, array $constructorArguments
    *
    * @return object
    *   The object receiving the data.
+   *
+   * @deprecated in drupal:10.2.0 and is removed from drupal:11.0.0. Use
+   *   supported modes only.
+   *
+   * @see https://www.drupal.org/node/3377999
    */
   protected function assocIntoObject(array $rowAssoc, object $object): object {
+    @trigger_error(__METHOD__ . '() is deprecated in drupal:10.2.0 and is removed from drupal:11.0.0. Use supported modes only. See https://www.drupal.org/node/3377999', E_USER_DEPRECATED);
     foreach ($rowAssoc as $column => $value) {
       $object->$column = $value;
     }
diff --git a/core/lib/Drupal/Core/Database/StatementPrefetchIterator.php b/core/lib/Drupal/Core/Database/StatementPrefetchIterator.php
index e88b3131173a56c6ced97c37c732acdaca915fa7..d12d41f903388992e9c733f53e1749bfe056a0e1 100644
--- a/core/lib/Drupal/Core/Database/StatementPrefetchIterator.php
+++ b/core/lib/Drupal/Core/Database/StatementPrefetchIterator.php
@@ -188,6 +188,9 @@ public function getQueryString() {
    * {@inheritdoc}
    */
   public function setFetchMode($mode, $a1 = NULL, $a2 = []) {
+    if (!in_array($mode, $this->supportedFetchModes)) {
+      @trigger_error('Fetch mode ' . ($this->fetchModeLiterals[$mode] ?? $mode) . ' is deprecated in drupal:10.2.0 and is removed from drupal:11.0.0. Use supported modes only. See https://www.drupal.org/node/3377999', E_USER_DEPRECATED);
+    }
     $this->defaultFetchStyle = $mode;
     switch ($mode) {
       case \PDO::FETCH_CLASS:
@@ -237,14 +240,18 @@ public function fetch($fetch_style = NULL, $cursor_orientation = \PDO::FETCH_ORI
 
     // Now, format the next prefetched record according to the required fetch
     // style.
+    // @todo in Drupal 11, remove arms for deprecated fetch modes.
     $rowAssoc = $this->data[$currentKey];
     $row = match($fetch_style ?? $this->defaultFetchStyle) {
       \PDO::FETCH_ASSOC => $rowAssoc,
+      // @phpstan-ignore-next-line
       \PDO::FETCH_BOTH => $this->assocToBoth($rowAssoc),
       \PDO::FETCH_NUM => $this->assocToNum($rowAssoc),
       \PDO::FETCH_LAZY, \PDO::FETCH_OBJ => $this->assocToObj($rowAssoc),
+      // @phpstan-ignore-next-line
       \PDO::FETCH_CLASS | \PDO::FETCH_CLASSTYPE => $this->assocToClassType($rowAssoc, $this->fetchOptions['constructor_args']),
       \PDO::FETCH_CLASS => $this->assocToClass($rowAssoc, $this->fetchOptions['class'], $this->fetchOptions['constructor_args']),
+      // @phpstan-ignore-next-line
       \PDO::FETCH_INTO => $this->assocIntoObject($rowAssoc, $this->fetchOptions['object']),
       \PDO::FETCH_COLUMN => $this->assocToColumn($rowAssoc, $this->columnNames, $this->fetchOptions['column']),
       // @todo in Drupal 11, throw an exception if the fetch style cannot be
@@ -297,6 +304,9 @@ public function fetchAssoc() {
    * {@inheritdoc}
    */
   public function fetchAll($mode = NULL, $column_index = NULL, $constructor_arguments = NULL) {
+    if (isset($mode) && !in_array($mode, $this->supportedFetchModes)) {
+      @trigger_error('Fetch mode ' . ($this->fetchModeLiterals[$mode] ?? $mode) . ' is deprecated in drupal:10.2.0 and is removed from drupal:11.0.0. Use supported modes only. See https://www.drupal.org/node/3377999', E_USER_DEPRECATED);
+    }
     $fetchStyle = $mode ?? $this->defaultFetchStyle;
     if (isset($column_index)) {
       $this->fetchOptions['column'] = $column_index;
diff --git a/core/lib/Drupal/Core/Database/StatementWrapperIterator.php b/core/lib/Drupal/Core/Database/StatementWrapperIterator.php
index 440b27e96da43b3b19b99dc502ce441d3f4fcac4..59738a2fab7f53caf0cefc88fb4d252c0f10c382 100644
--- a/core/lib/Drupal/Core/Database/StatementWrapperIterator.php
+++ b/core/lib/Drupal/Core/Database/StatementWrapperIterator.php
@@ -28,6 +28,7 @@
 class StatementWrapperIterator implements \Iterator, StatementInterface {
 
   use StatementIteratorTrait;
+  use FetchModeTrait;
 
   /**
    * The client database Statement object.
@@ -248,6 +249,9 @@ public function rowCount() {
    * {@inheritdoc}
    */
   public function setFetchMode($mode, $a1 = NULL, $a2 = []) {
+    if (!in_array($mode, $this->supportedFetchModes)) {
+      @trigger_error('Fetch mode ' . ($this->fetchModeLiterals[$mode] ?? $mode) . ' is deprecated in drupal:10.2.0 and is removed from drupal:11.0.0. Use supported modes only. See https://www.drupal.org/node/3377999', E_USER_DEPRECATED);
+    }
     // Call \PDOStatement::setFetchMode to set fetch mode.
     // \PDOStatement is picky about the number of arguments in some cases so we
     // need to be pass the exact number of arguments we where given.
@@ -262,6 +266,9 @@ public function setFetchMode($mode, $a1 = NULL, $a2 = []) {
    * {@inheritdoc}
    */
   public function fetch($mode = NULL, $cursor_orientation = NULL, $cursor_offset = NULL) {
+    if (isset($mode) && !in_array($mode, $this->supportedFetchModes)) {
+      @trigger_error('Fetch mode ' . ($this->fetchModeLiterals[$mode] ?? $mode) . ' is deprecated in drupal:10.2.0 and is removed from drupal:11.0.0. Use supported modes only. See https://www.drupal.org/node/3377999', E_USER_DEPRECATED);
+    }
     // Call \PDOStatement::fetchAll to fetch all rows.
     // \PDOStatement is picky about the number of arguments in some cases so we
     // need to pass the exact number of arguments we were given.
@@ -285,6 +292,9 @@ public function fetch($mode = NULL, $cursor_orientation = NULL, $cursor_offset =
    * {@inheritdoc}
    */
   public function fetchAll($mode = NULL, $column_index = NULL, $constructor_arguments = NULL) {
+    if (isset($mode) && !in_array($mode, $this->supportedFetchModes)) {
+      @trigger_error('Fetch mode ' . ($this->fetchModeLiterals[$mode] ?? $mode) . ' is deprecated in drupal:10.2.0 and is removed from drupal:11.0.0. Use supported modes only. See https://www.drupal.org/node/3377999', E_USER_DEPRECATED);
+    }
     // Call \PDOStatement::fetchAll to fetch all rows.
     // \PDOStatement is picky about the number of arguments in some cases so we
     // need to be pass the exact number of arguments we where given.
diff --git a/core/tests/Drupal/KernelTests/Core/Database/FetchTest.php b/core/tests/Drupal/KernelTests/Core/Database/FetchTest.php
index 8704425e2aaebfd76d85eeef982065d88c7a2e6b..73dc244bc39df6021bb2d8e9c60c655e0d053c31 100644
--- a/core/tests/Drupal/KernelTests/Core/Database/FetchTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Database/FetchTest.php
@@ -103,8 +103,11 @@ public function testQueryFetchObjectClass() {
    * The name of the class is determined from a value of the first column.
    *
    * @see \Drupal\Tests\system\Functional\Database\FakeRecord
+   *
+   * @group legacy
    */
   public function testQueryFetchClasstype() {
+    $this->expectDeprecation('Fetch mode FETCH_CLASS | FETCH_CLASSTYPE is deprecated in drupal:10.2.0 and is removed from drupal:11.0.0. Use supported modes only. See https://www.drupal.org/node/3377999');
     $records = [];
     $result = $this->connection->query('SELECT [classname], [name], [job] FROM {test_classtype} WHERE [age] = :age', [':age' => 26], ['fetch' => \PDO::FETCH_CLASS | \PDO::FETCH_CLASSTYPE]);
     foreach ($result as $record) {
@@ -136,8 +139,11 @@ public function testQueryFetchNum() {
 
   /**
    * Confirms that we can fetch a record into a doubly-keyed array explicitly.
+   *
+   * @group legacy
    */
   public function testQueryFetchBoth() {
+    $this->expectDeprecation('Fetch mode FETCH_BOTH is deprecated in drupal:10.2.0 and is removed from drupal:11.0.0. Use supported modes only. See https://www.drupal.org/node/3377999');
     $records = [];
     $result = $this->connection->query('SELECT [name] FROM {test} WHERE [age] = :age', [':age' => 25], ['fetch' => \PDO::FETCH_BOTH]);
     foreach ($result as $record) {
diff --git a/core/tests/Drupal/Tests/Core/Database/ConnectionTest.php b/core/tests/Drupal/Tests/Core/Database/ConnectionTest.php
index 28670b717533338d4b36e844463d805baff7df56..02c4c6b38fb3fe2a95b4667a8d8442b3505821fd 100644
--- a/core/tests/Drupal/Tests/Core/Database/ConnectionTest.php
+++ b/core/tests/Drupal/Tests/Core/Database/ConnectionTest.php
@@ -5,6 +5,7 @@
 use Composer\Autoload\ClassLoader;
 use Drupal\Core\Database\Database;
 use Drupal\Core\Database\StatementPrefetch;
+use Drupal\Core\Database\StatementPrefetchIterator;
 use Drupal\Tests\Core\Database\Stub\StubConnection;
 use Drupal\Tests\Core\Database\Stub\StubPDO;
 use Drupal\Tests\UnitTestCase;
@@ -906,4 +907,77 @@ public function testStatementPrefetchDeprecation() {
     $this->assertInstanceOf(StatementPrefetch::class, $statement);
   }
 
+  /**
+   * Provides data for testSupportedFetchModes.
+   *
+   * @return array
+   *   An associative array of simple arrays, each having the following
+   *   elements:
+   *   - a PDO fetch mode.
+   */
+  public static function providerSupportedFetchModes(): array {
+    return [
+      'FETCH_ASSOC' => [\PDO::FETCH_ASSOC],
+      'FETCH_CLASS' => [\PDO::FETCH_CLASS],
+      'FETCH_CLASS | FETCH_PROPS_LATE' => [\PDO::FETCH_CLASS | \PDO::FETCH_PROPS_LATE],
+      'FETCH_COLUMN' => [\PDO::FETCH_COLUMN],
+      'FETCH_NUM' => [\PDO::FETCH_NUM],
+      'FETCH_OBJ' => [\PDO::FETCH_OBJ],
+    ];
+  }
+
+  /**
+   * Tests supported fetch modes.
+   *
+   * @dataProvider providerSupportedFetchModes
+   */
+  public function testSupportedFetchModes(int $mode): void {
+    $mockPdo = $this->createMock(StubPDO::class);
+    $mockConnection = new StubConnection($mockPdo, []);
+    $statement = new StatementPrefetchIterator($mockPdo, $mockConnection, '');
+    $this->assertInstanceOf(StatementPrefetchIterator::class, $statement);
+    $statement->setFetchMode($mode);
+  }
+
+  /**
+   * Provides data for testDeprecatedFetchModes.
+   *
+   * @return array
+   *   An associative array of simple arrays, each having the following
+   *   elements:
+   *   - a PDO fetch mode.
+   */
+  public static function providerDeprecatedFetchModes(): array {
+    return [
+      'FETCH_DEFAULT' => [\PDO::FETCH_DEFAULT],
+      'FETCH_LAZY' => [\PDO::FETCH_LAZY],
+      'FETCH_BOTH' => [\PDO::FETCH_BOTH],
+      'FETCH_BOUND' => [\PDO::FETCH_BOUND],
+      'FETCH_INTO' => [\PDO::FETCH_INTO],
+      'FETCH_FUNC' => [\PDO::FETCH_FUNC],
+      'FETCH_NAMED' => [\PDO::FETCH_NAMED],
+      'FETCH_KEY_PAIR' => [\PDO::FETCH_KEY_PAIR],
+      'FETCH_CLASS | FETCH_CLASSTYPE' => [\PDO::FETCH_CLASS | \PDO::FETCH_CLASSTYPE],
+    ];
+  }
+
+  /**
+   * Tests deprecated fetch modes.
+   *
+   * @todo in drupal:11.0.0, do not remove this test but convert it to expect
+   *   exceptions instead of deprecations.
+   *
+   * @dataProvider providerDeprecatedFetchModes
+   *
+   * @group legacy
+   */
+  public function testDeprecatedFetchModes(int $mode): void {
+    $this->expectDeprecation('Fetch mode %A is deprecated in drupal:10.2.0 and is removed from drupal:11.0.0. Use supported modes only. See https://www.drupal.org/node/3377999');
+    $mockPdo = $this->createMock(StubPDO::class);
+    $mockConnection = new StubConnection($mockPdo, []);
+    $statement = new StatementPrefetchIterator($mockPdo, $mockConnection, '');
+    $this->assertInstanceOf(StatementPrefetchIterator::class, $statement);
+    $statement->setFetchMode($mode);
+  }
+
 }