diff --git a/config/install/tfa.settings.yml b/config/install/tfa.settings.yml
index f82ba91..606597a 100644
--- a/config/install/tfa.settings.yml
+++ b/config/install/tfa.settings.yml
@@ -1,6 +1,7 @@
 langcode: en
 enabled: false
 required_roles: { }
+forced: 0
 send_plugins: { }
 login_plugins: { }
 default_validation_plugin: ''
diff --git a/config/schema/tfa.schema.yml b/config/schema/tfa.schema.yml
index 53cb3db..c22c864 100644
--- a/config/schema/tfa.schema.yml
+++ b/config/schema/tfa.schema.yml
@@ -11,6 +11,9 @@ tfa.settings:
       sequence:
         type: string
         label: 'Role'
+    forced:
+      type: integer
+      label: 'Force required roles to setup when'
     send_plugins:
      type: sequence
      label: 'Enabled send plugins'
diff --git a/src/EventSubscriber/ForceTfaSetup.php b/src/EventSubscriber/ForceTfaSetup.php
new file mode 100644
index 0000000..2cbc2ad
--- /dev/null
+++ b/src/EventSubscriber/ForceTfaSetup.php
@@ -0,0 +1,134 @@
+<?php
+
+namespace Drupal\tfa\EventSubscriber;
+
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Messenger\MessengerInterface;
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Session\AccountProxyInterface;
+use Drupal\Core\Url;
+use Drupal\tfa\TfaLoginContextTrait;
+use Drupal\tfa\TfaPluginManager;
+use Drupal\user\UserDataInterface;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\HttpFoundation\RedirectResponse;
+use Symfony\Component\HttpKernel\Event\RequestEvent;
+use Symfony\Component\HttpKernel\KernelEvents;
+
+/**
+ * Event subscriber for enforcing TFA.
+ */
+class ForceTfaSetup implements EventSubscriberInterface {
+  use TfaLoginContextTrait;
+
+  /**
+   * The route match.
+   *
+   * @var \Drupal\Core\Routing\RouteMatchInterface
+   */
+  protected $routeMatch;
+
+  /**
+   * The messenger.
+   *
+   * @var \Drupal\Core\Messenger\MessengerInterface
+   */
+  protected $messenger;
+
+  /**
+   * Current user.
+   *
+   * @var \Drupal\Core\Session\AccountProxyInterface
+   */
+  protected $currentUser;
+
+  /**
+   * The user storage.
+   *
+   * @var \Drupal\user\UserStorageInterface
+   */
+  protected $userStorage;
+
+  /**
+   * Constructs an AutologoutSubscriber object.
+   *
+   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+   *   The route match.
+   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
+   *   The messenger.
+   * @param \Drupal\Core\Session\AccountProxyInterface $current_user
+   *   The current user.
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   The config factory.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager.
+   * @param \Drupal\user\UserDataInterface $user_data
+   *   The user data.
+   * @param \Drupal\tfa\TfaPluginManager $tfa_plugin_manager
+   *   The TFA plugin manager.
+   */
+  public function __construct(RouteMatchInterface $route_match, MessengerInterface $messenger, AccountProxyInterface $current_user, ConfigFactoryInterface $config_factory, EntityTypeManagerInterface $entity_type_manager, UserDataInterface $user_data, TfaPluginManager $tfa_plugin_manager) {
+    $this->messenger = $messenger;
+    $this->routeMatch = $route_match;
+    $this->currentUser = $current_user;
+    $this->userStorage = $entity_type_manager->getStorage('user');
+    $this->tfaSettings = $config_factory->get('tfa.settings');
+    $this->userData = $user_data;
+    $this->tfaPluginManager = $tfa_plugin_manager;
+  }
+
+  /**
+   * Redirect users to TFA overview when no remaining skips.
+   *
+   * @param \Symfony\Component\HttpKernel\Event\RequestEvent $event
+   *   The request event.
+   */
+  public function redirect(RequestEvent $event): void {
+    /** @var \Drupal\user\UserInterface $user */
+    $user = $this->userStorage->load($this->currentUser->id());
+    $this->setUser($user);
+
+    if ($this->isReady() || !$this->forceTFASetup()) {
+      return;
+    }
+
+    $this->messenger->addWarning(t('You need to enable Two Factor Authentication.'));
+
+    // Don't redirect the user if on password/profile edit page,
+    // as it is possible the user used one-time login URL
+    // and need to change the password.
+    $ignored_route_names = [
+      'user.login',
+      'user.logout',
+      'user.pass',
+      'user.edit',
+      'entity.user.edit_form',
+      'user.reset.login',
+      'user.reset',
+      'user.reset.form',
+      'user.well-known.change_password',
+      'tfa.entry',
+      'tfa.login',
+      'tfa.overview',
+      'tfa.validation.setup',
+      'tfa.disable',
+      'tfa.plugin.reset',
+    ];
+    if (in_array($this->routeMatch->getRouteName(), $ignored_route_names)) {
+      return;
+    }
+
+    $tfa_overview_url = Url::fromRoute('tfa.overview', ['user' => $this->user->id()]);
+    $event->setResponse(new RedirectResponse($tfa_overview_url->toString()));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getSubscribedEvents(): array {
+    $events[KernelEvents::REQUEST][] = ['redirect', 32];
+    return $events;
+  }
+
+}
diff --git a/src/Form/SettingsForm.php b/src/Form/SettingsForm.php
index cb6ec38..64aa978 100644
--- a/src/Form/SettingsForm.php
+++ b/src/Form/SettingsForm.php
@@ -143,6 +143,14 @@ class SettingsForm extends ConfigFormBase {
       '#required' => FALSE,
     ];
 
+    $form['tfa_forced'] = [
+      '#type' => 'checkbox',
+      '#title' => $this->t('Force TFA setup'),
+      '#default_value' => $config->get('forced'),
+      '#description' => $this->t('Force TFA setup on login, redirect user to FTA overview page.'),
+      '#states' => $enabled_state,
+    ];
+
     $form['tfa_allowed_validation_plugins'] = [
       '#type' => 'checkboxes',
       '#title' => $this->t('Allowed Validation plugins'),
@@ -231,7 +239,14 @@ class SettingsForm extends ConfigFormBase {
       '#min' => 0,
       '#max' => 99,
       '#size' => 2,
-      '#states' => $enabled_state,
+      '#states' => [
+        'visible' => [
+          [
+            ':input[name="tfa_enabled"]' => ['checked' => TRUE],
+            ':input[name="tfa_forced"]' => ['checked' => FALSE],
+          ],
+        ],
+      ],
       '#required' => TRUE,
     ];
 
@@ -431,6 +446,7 @@ class SettingsForm extends ConfigFormBase {
     $this->config('tfa.settings')
       ->set('enabled', $form_state->getValue('tfa_enabled'))
       ->set('required_roles', $form_state->getValue('tfa_required_roles'))
+      ->set('forced', $form_state->getValue('tfa_forced'))
       ->set('send_plugins', array_filter($send_plugins))
       ->set('login_plugins', array_filter($login_plugins))
       ->set('login_plugin_settings', $form_state->getValue('login_plugin_settings'))
diff --git a/src/Form/TfaLoginForm.php b/src/Form/TfaLoginForm.php
index 08fd712..c448675 100644
--- a/src/Form/TfaLoginForm.php
+++ b/src/Form/TfaLoginForm.php
@@ -143,9 +143,15 @@ class TfaLoginForm extends UserLoginForm {
    *   The state of the login form.
    */
   protected function loginWithoutTfa(FormStateInterface $form_state) {
+    if ($this->forceTFASetup()) {
+      $this->doUserLogin();
+      return;
+    }
+
     // User may be able to skip TFA, depending on module settings and number of
     // prior attempts.
     $remaining = $this->remainingSkips();
+
     if ($remaining) {
       $user = $this->getUser();
       $tfa_setup_link = Url::fromRoute('tfa.overview', [
@@ -161,12 +167,12 @@ class TfaLoginForm extends UserLoginForm {
       $this->hasSkipped();
       $this->doUserLogin();
       $form_state->setRedirect('<front>');
+      return;
     }
-    else {
-      $message = $this->config('tfa.settings')->get('help_text');
-      $this->messenger()->addError($message);
-      $this->logger('tfa')->notice('@name has no more remaining attempts for bypassing the second authentication factor.', ['@name' => $this->getUser()->getAccountName()]);
-    }
+
+    $message = $this->config('tfa.settings')->get('help_text');
+    $this->messenger()->addError($message);
+    $this->logger('tfa')->notice('@name has no more remaining attempts for bypassing the second authentication factor.', ['@name' => $this->getUser()->getAccountName()]);
   }
 
   /**
diff --git a/src/Form/TfaOverviewForm.php b/src/Form/TfaOverviewForm.php
index 99026be..aa61190 100644
--- a/src/Form/TfaOverviewForm.php
+++ b/src/Form/TfaOverviewForm.php
@@ -159,13 +159,15 @@ class TfaOverviewForm extends FormBase {
         }
       }
 
-      $output['validation_skip_status'] = [
-        '#type'   => 'markup',
-        '#markup' => '<p>' . $this->t('Number of times validation skipped: @skipped of @limit', [
-          '@skipped' => $user_tfa['validation_skipped'] ?? 0,
-          '@limit' => $config->get('validation_skip'),
-        ]) . '</p>',
-      ];
+      if (!$config->get('forced')) {
+        $output['validation_skip_status'] = [
+          '#type' => 'markup',
+          '#markup' => '<p>' . $this->t('Number of times validation skipped: @skipped of @limit', [
+              '@skipped' => $user_tfa['validation_skipped'] ?? 0,
+              '@limit' => $config->get('validation_skip'),
+            ]) . '</p>',
+        ];
+      }
     }
     else {
       $output['disabled'] = [
diff --git a/src/TfaLoginContextTrait.php b/src/TfaLoginContextTrait.php
index 342c1c9..d944fa4 100644
--- a/src/TfaLoginContextTrait.php
+++ b/src/TfaLoginContextTrait.php
@@ -84,6 +84,17 @@ trait TfaLoginContextTrait {
     return empty(array_intersect($required_roles, $this->user->getRoles()));
   }
 
+  /**
+   * Should we force TFA setup?
+   *
+   * @return bool
+   *   TRUE if TFA is enabled and there are no remaining skips left.
+   */
+  public function forceTFASetup(): bool {
+    return !$this->isTfaDisabled()
+      && $this->tfaSettings->get('forced');
+  }
+
   /**
    * Check whether the Validation Plugin is set and ready for use.
    *
diff --git a/tests/src/Functional/ForceTfaSetupTest.php b/tests/src/Functional/ForceTfaSetupTest.php
new file mode 100644
index 0000000..ff8798b
--- /dev/null
+++ b/tests/src/Functional/ForceTfaSetupTest.php
@@ -0,0 +1,99 @@
+<?php
+
+namespace Drupal\Tests\tfa\Functional;
+
+/**
+ * Tests for the tfa setup enforcement.
+ *
+ * @group Tfa
+ */
+class ForceTfaSetupTest extends TfaTestBase {
+
+  /**
+   * User doing the TFA Validation.
+   *
+   * @var \Drupal\user\Entity\User
+   */
+  protected $webUser;
+
+  /**
+   * Administrator to handle configurations.
+   *
+   * @var \Drupal\user\Entity\User
+   */
+  protected $adminUser;
+
+  /**
+   * TFA settings.
+   *
+   * @var \Drupal\Core\Config\Config
+   */
+  protected $config;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() : void {
+    parent::setUp();
+    $this->webUser = $this->drupalCreateUser(['setup own tfa']);
+    $this->adminUser = $this->drupalCreateUser(['admin tfa settings']);
+    $this->config = $this->config('tfa.settings');
+    $this->config->set('validation_skip', 2)
+      ->set('enabled', 1)
+      ->set('forced', 1)
+      ->set('default_validation_plugin', 'tfa_recovery_code')
+      ->set('allowed_validation_plugins', ['tfa_recovery_code' => 'tfa_recovery_code'])
+      ->set('encryption', $this->encryptionProfile->id())
+      ->save();
+  }
+
+  /**
+   * Tests the tfa login process.
+   */
+  public function testTfaLogin() {
+    $assert_session = $this->assertSession();
+
+    // Setup enforcement is not active when the user roles are not required.
+    $this->drupalLogin($this->webUser);
+    $assert_session->statusCodeEquals(200);
+    $assert_session->addressEquals('user/' . $this->webUser->id());
+
+    // Make it required.
+    $web_user_roles = $this->webUser->getRoles(TRUE);
+    $this->config->set('required_roles', [$web_user_roles[0] => $web_user_roles[0]])
+      ->save();
+
+    // The User is redirected to the tfa page.
+    $this->drupalLogout();
+    $this->drupalLogin($this->webUser);
+    $assert_session->statusCodeEquals(200);
+    $assert_session->addressEquals('user/' . $this->webUser->id() . '/security/tfa');
+
+    // Disable again.
+    $this->config->set('forced', 0)->save();
+    $this->drupalGet('user/' . $this->webUser->id());
+    $assert_session->statusCodeEquals(200);
+    $assert_session->addressEquals('user/' . $this->webUser->id());
+
+    // Re-enable.
+    $this->config->set('forced', 1)->save();
+    $this->drupalGet('user/' . $this->webUser->id());
+    $assert_session->statusCodeEquals(200);
+    $assert_session->addressEquals('user/' . $this->webUser->id() . '/security/tfa');
+
+    $this->clickLink('Generate codes');
+    $assert_session->statusCodeEquals(200);
+    $assert_session->pageTextContains('Enter your current password to continue.');
+    $edit = [
+      'current_pass' => $this->webUser->passRaw,
+    ];
+    $this->submitForm($edit, 'Confirm');
+    $this->submitForm([], 'Save codes to account');
+
+    // Other pages can be visited now.
+    $this->drupalGet('user/' . $this->webUser->id());
+    $assert_session->statusCodeEquals(200);
+    $assert_session->addressEquals('user/' . $this->webUser->id());
+  }
+
+}
diff --git a/tfa.services.yml b/tfa.services.yml
index 7d56d23..69c3a6e 100644
--- a/tfa.services.yml
+++ b/tfa.services.yml
@@ -8,3 +8,8 @@ services:
     class: Drupal\tfa\Routing\TfaRouteSubscriber
     tags:
       - { name: event_subscriber }
+  tfa.force_setup:
+    class: Drupal\tfa\EventSubscriber\ForceTfaSetup
+    arguments: ['@current_route_match', '@messenger', '@current_user', '@config.factory', '@entity_type.manager', '@user.data', '@plugin.manager.tfa']
+    tags:
+      - { name: event_subscriber }
