diff --git a/core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php b/core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php
index 04da0f5..66e7b04 100644
--- a/core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php
+++ b/core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php
@@ -27,6 +27,16 @@ class MigrateUpgradeForm extends ConfirmFormBase {
   use MigrationConfigurationTrait;
 
   /**
+   * If a migration has previously run, perform an incremental migration.
+   */
+  const MIGRATE_UPGRADE_INCREMENTAL = 1;
+
+  /**
+   * If a migration has previously run, roll it back and start fresh.
+   */
+  const MIGRATE_UPGRADE_ROLLBACK = 2;
+
+  /**
    * The state service.
    *
    * @var \Drupal\Core\State\StateInterface
@@ -262,10 +272,18 @@ public function buildOverviewForm(array $form, FormStateInterface $form_state) {
       //   https://www.drupal.org/node/2687849
       $form['upgrade_option_item'] = [
         '#type' => 'item',
-        '#prefix' => $this->t('An upgrade has already been performed on this site. To perform a new migration, create a clean and empty new install of Drupal 8. Rollbacks and incremental migrations are not yet supported through the user interface. For more information, see the <a href=":url">upgrading handbook</a>.', [':url' => 'https://www.drupal.org/upgrade/migrate']),
+        '#prefix' => $this->t('An upgrade has already been performed on this site.'),
         '#description' => $this->t('Last upgrade: @date', ['@date' => $this->dateFormatter->format($date_performed)]),
       ];
-      return $form;
+      $form['upgrade_option'] = array(
+        '#type' => 'radios',
+        '#title' => $this->t('You can rollback the upgrade.'),
+        '#default_value' => static::MIGRATE_UPGRADE_ROLLBACK,
+        '#options' => [
+          static::MIGRATE_UPGRADE_ROLLBACK => $this->t('<strong>Rollback</strong>: Remove content and configuration entities (such as fields and node types). Default values of other configuration will not be reverted (such as site name).'),
+        ],
+      );
+      $validate = ['::validateCredentialForm'];
     }
     else {
       $form['info_header'] = [
@@ -328,6 +346,14 @@ public function buildOverviewForm(array $form, FormStateInterface $form_state) {
    */
   public function submitOverviewForm(array &$form, FormStateInterface $form_state) {
     $form_state->set('step', 'credentials');
+    switch ($form_state->getValue('upgrade_option')) {
+      case static::MIGRATE_UPGRADE_ROLLBACK:
+        $form_state->setValue('step', 'confirm');
+        break;
+      default:
+        $form_state->setValue('step', 'credentials');
+        break;
+    }
     $form_state->setRebuild();
   }
 
@@ -476,6 +502,10 @@ public function buildCredentialForm(array $form, FormStateInterface $form_state)
    *   The current state of the form.
    */
   public function validateCredentialForm(array &$form, FormStateInterface $form_state) {
+    // Skip if rollback was chosen.
+    if ($form_state->getValue('upgrade_option') == static::MIGRATE_UPGRADE_ROLLBACK) {
+      return;
+    }
 
     // Retrieve the database driver from the form, use reflection to get the
     // namespace, and then construct a valid database array the same as in
@@ -712,7 +742,7 @@ public function submitConfirmIdConflictForm(array &$form, FormStateInterface $fo
   }
 
   /**
-   * Confirmation form showing available and missing migration paths.
+   * Confirmation form showing rollbacks, available and missing migration paths.
    *
    * The confirmation form uses the source_module and destination_module
    * properties on the source, destination and field plugins as well as the
@@ -733,6 +763,17 @@ public function buildConfirmForm(array $form, FormStateInterface $form_state) {
 
     $form['actions']['submit']['#value'] = $this->t('Perform upgrade');
 
+    if ($rollback = $form_state->getValue('upgrade_option') == static::MIGRATE_UPGRADE_ROLLBACK) {
+      $form_state->setStorage(['upgrade_option' => static::MIGRATE_UPGRADE_ROLLBACK]);
+      $form['rollback'] = [
+        '#markup' => $this->t('All previously-imported content, as well as configuration such as field definitions, will be removed.')
+      ];
+      $form['actions']['submit']['#value'] = $this->t('Perform rollback');
+    }
+    else {
+      $form['actions']['submit']['#value'] = $this->t('Perform upgrade');
+    }
+
     $version = $form_state->get('version');
 
     // Get the source_module and destination_module for each migration.
@@ -924,24 +965,63 @@ public function buildConfirmForm(array $form, FormStateInterface $form_state) {
   public function submitConfirmForm(array &$form, FormStateInterface $form_state) {
     $storage = $form_state->getStorage();
 
-    $migrations = $storage['migrations'];
-    $config['source_base_path'] = $storage['source_base_path'];
-    $batch = [
-      'title' => $this->t('Running upgrade'),
-      'progress_message' => '',
-      'operations' => [
-        [
-          [MigrateUpgradeImportBatch::class, 'run'],
-          [array_keys($migrations), $config],
+    if (isset($storage['upgrade_option']) && $storage['upgrade_option'] == static::MIGRATE_UPGRADE_ROLLBACK) {
+      $migrations = $this->pluginManager->createInstances([]);
+      // Assume we want all those tagged 'Drupal %'.
+      foreach ($migrations as $migration_id => $migration) {
+        $keep = FALSE;
+        $tags = $migration->get('migration_tags');
+        foreach ($tags as $tag) {
+          if (strpos($tag, 'Drupal ') === 0) {
+            $keep = TRUE;
+            break;
+          }
+        }
+        if (!$keep) {
+          unset($migrations[$migration_id]);
+        }
+      }
+      // Roll back in reverse order.
+      $migrations = array_reverse($migrations);
+      $batch = [
+        'title' => $this->t('Rolling back upgrade'),
+        'progress_message' => '',
+        'operations' => [
+          [
+            [MigrateUpgradeRunBatch::class, 'run'],
+            [array_keys($migrations), 'rollback', []],
+          ],
         ],
-      ],
-      'finished' => [
-        MigrateUpgradeImportBatch::class, 'finished',
-      ],
-    ];
-    batch_set($batch);
-    $form_state->setRedirect('<front>');
-    $this->state->set('migrate_drupal_ui.performed', REQUEST_TIME);
+        'finished' => [
+          MigrateUpgradeRunBatch::class,
+          'finished',
+          ],
+      ];
+      batch_set($batch);
+      $form_state->setRedirect('migrate_drupal_ui.upgrade');
+      $this->state->delete('migrate_drupal_ui.performed');
+    }
+    else {
+      $migrations = $storage['migrations'];
+      $config['source_base_path'] = $storage['source_base_path'];
+      $batch = [
+        'title' => $this->t('Running upgrade'),
+        'progress_message' => '',
+        'operations' => [
+          [
+            [MigrateUpgradeRunBatch::class, 'run'],
+            [array_keys($migrations), 'import', $config],
+          ],
+        ],
+        'finished' => [
+          MigrateUpgradeRunBatch::class,
+          'finished',
+        ],
+      ];
+      batch_set($batch);
+      $form_state->setRedirect('<front>');
+      $this->state->set('migrate_drupal_ui.performed', REQUEST_TIME);
+    }
   }
 
   /**
@@ -960,7 +1040,12 @@ protected function getDatabaseTypes() {
    * {@inheritdoc}
    */
   public function getQuestion() {
-    return $this->t('Upgrade analysis report');
+    if ($this->state->get('migrate_drupal_ui.performed')) {
+      return $this->t('Are you sure you want to rollback the migration?');
+    }
+    else {
+      return $this->t('Upgrade analysis report');
+    }
   }
 
   /**
@@ -976,7 +1061,12 @@ public function getCancelUrl() {
   public function getDescription() {
     // The description is added by the buildConfirmForm() method.
     // @see \Drupal\migrate_drupal_ui\Form\MigrateUpgradeForm::buildConfirmForm()
-    return;
+    if ($this->state->get('migrate_drupal_ui.performed')) {
+      return;
+    }
+    else {
+      return $this->t('<p><strong>Upgrade analysis report</strong></p>');
+    }
   }
 
   /**
