diff --git a/core/modules/image/src/Tests/Migrate/d6/MigrateImageCacheTest.php b/core/modules/image/src/Tests/Migrate/d6/MigrateImageCacheTest.php
index 68efb34338c097a95fc30e2379df63e48f7c2c11..d4a7b4308f8ceda2e4c5677e72957935c7807c15 100644
--- a/core/modules/image/src/Tests/Migrate/d6/MigrateImageCacheTest.php
+++ b/core/modules/image/src/Tests/Migrate/d6/MigrateImageCacheTest.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Database\Database;
 use Drupal\image\Entity\ImageStyle;
 use \Drupal\image\ConfigurableImageEffectBase;
+use Drupal\migrate\Entity\MigrationInterface;
 use Drupal\migrate\MigrateException;
 use Drupal\migrate_drupal\Tests\d6\MigrateDrupal6TestBase;
 
@@ -105,9 +106,15 @@ public function testMissingEffectPlugin() {
 
      $this->startCollectingMessages();
      $this->executeMigration('d6_imagecache_presets');
-     $this->assertEqual(['error' => [
-       'The "image_deprecated_scale" plugin does not exist.'
-     ]], $this->migrateMessages);
+     $messages = $this->migration->getIdMap()->getMessageIterator();
+     $count = 0;
+     foreach ($messages as $message) {
+       $count++;
+       $this->assertEqual($message->message, 'The "image_deprecated_scale" plugin does not exist.');
+       $this->assertEqual($message->level, MigrationInterface::MESSAGE_ERROR);
+     }
+     // There should be only the one message.
+     $this->assertEqual($count, 1);
   }
 
   /**
diff --git a/core/modules/migrate/src/Plugin/MigrateIdMapInterface.php b/core/modules/migrate/src/Plugin/MigrateIdMapInterface.php
index df392f0bcee7bb1a501c37da22d570fee12513c2..d6f17df34421b9d10f905ba948dde6561d32af6c 100644
--- a/core/modules/migrate/src/Plugin/MigrateIdMapInterface.php
+++ b/core/modules/migrate/src/Plugin/MigrateIdMapInterface.php
@@ -65,6 +65,20 @@ public function saveIdMapping(Row $row, array $destination_id_values, $status =
    */
   public function saveMessage(array $source_id_values, $message, $level = MigrationInterface::MESSAGE_ERROR);
 
+  /**
+   * Retrieves an iterator over messages relate to source records.
+   *
+   * @param array $source_id_values
+   *   (optional) The source identifier values of a specific record to retrieve.
+   *   If empty, all messages are retrieved.
+   * @param int $level
+   *   (optional) Message severity. If NULL, retrieve messages of all severities.
+   *
+   * @return \Iterator
+   *   Retrieves an iterator over the message rows.
+   */
+  public function getMessageIterator(array $source_id_values = [], $level = NULL);
+
   /**
    * Prepares to run a full update.
    *
diff --git a/core/modules/migrate/src/Plugin/migrate/id_map/Sql.php b/core/modules/migrate/src/Plugin/migrate/id_map/Sql.php
index fdf940d4e5b0e444dbc8e62e4dfd5c87fe806ce4..ef2f03e77ebc433b0fb911e9147ba179e519a8cd 100644
--- a/core/modules/migrate/src/Plugin/migrate/id_map/Sql.php
+++ b/core/modules/migrate/src/Plugin/migrate/id_map/Sql.php
@@ -559,6 +559,22 @@ public function saveMessage(array $source_id_values, $message, $level = Migratio
       ->execute();
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getMessageIterator(array $source_id_values = [], $level = NULL) {
+    $query = $this->getDatabase()->select($this->messageTableName(), 'msg')
+      ->fields('msg');
+    $count = 1;
+    foreach ($source_id_values as $id_value) {
+      $query->condition('sourceid' . $count++, $id_value);
+    }
+    if ($level) {
+      $query->condition('level', $level);
+    }
+    return $query->execute();
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/migrate/tests/src/Unit/MigrateSqlIdMapTest.php b/core/modules/migrate/tests/src/Unit/MigrateSqlIdMapTest.php
index 1a9d70a6a0302535ddebcd5b0626984c529b2cb6..3460ca3e1ab2df60c694976abd8a7d613abc4d0f 100644
--- a/core/modules/migrate/tests/src/Unit/MigrateSqlIdMapTest.php
+++ b/core/modules/migrate/tests/src/Unit/MigrateSqlIdMapTest.php
@@ -287,25 +287,34 @@ public function testMessageSave() {
 
     foreach ($expected_results as $key => $expected_result) {
       $id_map->saveMessage([$key], $message, $expected_result['level']);
-      $message_row = $this->database->select($id_map->messageTableName(), 'message')
-                       ->fields('message')
-                       ->condition('level', $expected_result['level'])
-                       ->condition('message', $expected_result['message'])
-                       ->execute()
-                       ->fetchAssoc();
-      $this->assertEquals($expected_result['message'], $message_row['message'], 'Message from database was read.');
+    }
+
+    foreach ($id_map->getMessageIterator() as $message_row) {
+      $key = $message_row->sourceid1;
+      $this->assertEquals($expected_results[$key]['message'], $message_row->message);
+      $this->assertEquals($expected_results[$key]['level'], $message_row->level);
     }
 
     // Insert with default level.
     $message_default = 'Hello world default.';
     $id_map->saveMessage([5], $message_default);
-    $message_row = $this->database->select($id_map->messageTableName(), 'message')
-                     ->fields('message')
-                     ->condition('level', MigrationInterface::MESSAGE_ERROR)
-                     ->condition('message', $message_default)
-                     ->execute()
-                     ->fetchAssoc();
-    $this->assertEquals($message_default, $message_row['message'], 'Message from database was read.');
+    $messages = $id_map->getMessageIterator([5]);
+    $count = 0;
+    foreach ($messages as $key => $message_row) {
+      $count = 1;
+      $this->assertEquals($message_default, $message_row->message);
+      $this->assertEquals(MigrationInterface::MESSAGE_ERROR, $message_row->level);
+    }
+    $this->assertEquals($count, 1);
+
+    // Retrieve messages with a specific level.
+    $messages = $id_map->getMessageIterator([], MigrationInterface::MESSAGE_WARNING);
+    $count = 0;
+    foreach ($messages as $key => $message_row) {
+      $count = 1;
+      $this->assertEquals(MigrationInterface::MESSAGE_WARNING, $message_row->level);
+    }
+    $this->assertEquals($count, 1);
   }
 
   /**