diff --git a/typo3/sysext/core/Documentation/Changelog/13.3/Feature-104655-AddConsoleCommandToMarkUpgradeWizardsAsUndone.rst b/typo3/sysext/core/Documentation/Changelog/13.3/Feature-104655-AddConsoleCommandToMarkUpgradeWizardsAsUndone.rst
new file mode 100644
index 0000000000000000000000000000000000000000..104927e113be64acb6fc831065d85472e2ef9945
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/13.3/Feature-104655-AddConsoleCommandToMarkUpgradeWizardsAsUndone.rst
@@ -0,0 +1,33 @@
+.. include:: /Includes.rst.txt
+
+.. _feature-104655-1724859386:
+
+========================================================================
+Feature: #104655 - Add console command to mark upgrade wizards as undone
+========================================================================
+
+See :issue:`104655`
+
+Description
+===========
+
+A new CLI command :bash:`typo3 upgrade:mark:undone` has been
+introduced. It allows to mark a previously executed upgrade wizard as "undone",
+so it can be run again.
+
+This makes the existing functionality from the install tool also available on
+CLI.
+
+..  note::
+
+    Bear in mind that wizards theoretically can cause data inconsistencies when
+    being run again. Also, a wizard may not run properly again when its
+    pre-requisites no longer apply after its first run.
+
+Impact
+======
+
+You can now mark an already executed upgrade wizard as "undone" with
+:bash:`typo3 upgrade:markUndone <wizardIdentifier>`
+
+.. index:: CLI, ext:install
diff --git a/typo3/sysext/install/Classes/Command/UpgradeWizardMarkUndoneCommand.php b/typo3/sysext/install/Classes/Command/UpgradeWizardMarkUndoneCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..d39d30f5c30c2103a808dbc91d5d443a14fb3f3b
--- /dev/null
+++ b/typo3/sysext/install/Classes/Command/UpgradeWizardMarkUndoneCommand.php
@@ -0,0 +1,87 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+namespace TYPO3\CMS\Install\Command;
+
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+use TYPO3\CMS\Core\Authentication\CommandLineUserAuthentication;
+use TYPO3\CMS\Core\Core\Bootstrap;
+use TYPO3\CMS\Install\Service\LateBootService;
+use TYPO3\CMS\Install\Service\UpgradeWizardsService;
+
+/**
+ * Upgrade wizard command for marking wizards as undone
+ *
+ * @internal
+ */
+class UpgradeWizardMarkUndoneCommand extends Command
+{
+    private UpgradeWizardsService $upgradeWizardsService;
+
+    public function __construct(
+        string $name,
+        private readonly LateBootService $lateBootService
+    ) {
+        parent::__construct($name);
+    }
+
+    /**
+     * Bootstrap running of upgradeWizards
+     */
+    protected function bootstrap(): void
+    {
+        $this->upgradeWizardsService = $this->lateBootService
+            ->loadExtLocalconfDatabaseAndExtTables(false)
+            ->get(UpgradeWizardsService::class);
+        Bootstrap::initializeBackendUser(CommandLineUserAuthentication::class);
+        Bootstrap::initializeBackendAuthentication();
+    }
+
+    /**
+     * Configure the command by defining the name, options and arguments
+     */
+    protected function configure(): void
+    {
+        $this->setDescription('Mark upgrade wizard as undone.')
+            ->addArgument(
+                'wizardIdentifier',
+                InputArgument::REQUIRED
+            );
+    }
+
+    /**
+     * Mark an upgrade wizard as undone
+     */
+    protected function execute(InputInterface $input, OutputInterface $output): int
+    {
+        $io = new SymfonyStyle($input, $output);
+        $this->bootstrap();
+        $wizardIdentifier = (string)$input->getArgument('wizardIdentifier');
+        $wizardInformation = $this->upgradeWizardsService->getWizardInformationByIdentifier($wizardIdentifier);
+        $hasBeenMarkedUndone = $this->upgradeWizardsService->markWizardUndone($wizardIdentifier);
+        if ($hasBeenMarkedUndone) {
+            $io->success('The wizard "' . $wizardInformation['title'] . '" has been marked as undone.');
+            return Command::SUCCESS;
+        }
+        $io->error('The wizard "' . $wizardInformation['title'] . '" could not be marked undone, because it was most likely not yet run.');
+        return Command::FAILURE;
+    }
+}
diff --git a/typo3/sysext/install/Classes/ServiceProvider.php b/typo3/sysext/install/Classes/ServiceProvider.php
index 45acdc612da63c344b94d078e8efa28c059642ab..2a512cf16d89f6b56bfce6b464a800e120690af7 100644
--- a/typo3/sysext/install/Classes/ServiceProvider.php
+++ b/typo3/sysext/install/Classes/ServiceProvider.php
@@ -104,6 +104,7 @@ class ServiceProvider extends AbstractServiceProvider
             Command\LanguagePackCommand::class => self::getLanguagePackCommand(...),
             Command\UpgradeWizardRunCommand::class => self::getUpgradeWizardRunCommand(...),
             Command\UpgradeWizardListCommand::class => self::getUpgradeWizardListCommand(...),
+            Command\UpgradeWizardMarkUndoneCommand::class => self::getUpgradeWizardMarkUndoneCommand(...),
             Command\SetupCommand::class => self::getSetupCommand(...),
             Command\SetupDefaultBackendUserGroupsCommand::class => self::getSetupDefaultBackendUserGroupsCommand(...),
             Database\PermissionsCheck::class => self::getPermissionsCheck(...),
@@ -396,6 +397,14 @@ class ServiceProvider extends AbstractServiceProvider
         );
     }
 
+    public static function getUpgradeWizardMarkUndoneCommand(ContainerInterface $container): Command\UpgradeWizardMarkUndoneCommand
+    {
+        return new Command\UpgradeWizardMarkUndoneCommand(
+            'upgrade:mark:undone',
+            $container->get(Service\LateBootService::class),
+        );
+    }
+
     public static function getSetupCommand(ContainerInterface $container): Command\SetupCommand
     {
         return new Command\SetupCommand(
@@ -455,6 +464,11 @@ class ServiceProvider extends AbstractServiceProvider
             Command\UpgradeWizardListCommand::class,
             'List available upgrade wizards.'
         );
+        $commandRegistry->addLazyCommand(
+            'upgrade:mark:undone',
+            Command\UpgradeWizardMarkUndoneCommand::class,
+            'Mark upgrade wizard as undone.'
+        );
         $commandRegistry->addLazyCommand(
             'setup',
             Command\SetupCommand::class,