diff --git a/config/install/restrict_ip.settings.yml b/config/install/restrict_ip.settings.yml
index 71b69c1068b126d9db29a608a6f00754c67ebed5..0b8915ec4bf9211cf2d939b695cebe2d05353697 100644
--- a/config/install/restrict_ip.settings.yml
+++ b/config/install/restrict_ip.settings.yml
@@ -18,6 +18,9 @@ allow_role_bypass: false
 # A key indicating what action should be performed when bypasses are allowed by role, but users are not logged in
 bypass_action: 'provide_link_login_page'
 
+# A boolean indicating whether to return a 403 access denied response when blocking.
+return_403: false
+
 # D7 variable - restrict_ip_white_black_list
 # An integer indicating how to check bypass restrictions.
 #   0 = check access on all paths
diff --git a/config/schema/restrict_ip.schema.yml b/config/schema/restrict_ip.schema.yml
index 84899315f5680e25c21eb18a11498db82ae166c8..f36df7e13a70abae2f97657918a8cfd27afa8b09 100644
--- a/config/schema/restrict_ip.schema.yml
+++ b/config/schema/restrict_ip.schema.yml
@@ -23,6 +23,9 @@ restrict_ip.settings:
         Choice:
           - provide_link_login_page
           - redirect_login_page
+    return_403:
+      type: boolean
+      label: 'Return a 403 access denied response when blocking'
     white_black_list:
       type: integer
       label: 'Whether to use a path whitelist, blacklist, or check all pages'
diff --git a/restrict_ip.install b/restrict_ip.install
index c9e308fbce399accdc505a13e76017f7b0e5273f..084899c1d4c97bb04797c25e2303ab28f42aa7a2 100644
--- a/restrict_ip.install
+++ b/restrict_ip.install
@@ -142,3 +142,12 @@ function restrict_ip_update_500001(): void {
 function restrict_ip_update_500002(): void {
   \Drupal::configFactory()->getEditable('restrict_ip.settings')->save();
 }
+
+/**
+ * Ensure the new return_403 option is present in config (disabled by default).
+ */
+function restrict_ip_update_500003(): void {
+  \Drupal::configFactory()->getEditable('restrict_ip.settings')
+    ->set('return_403', FALSE)
+    ->save();
+}
diff --git a/restrict_ip.services.yml b/restrict_ip.services.yml
index a027553129520723ffffd8f799a042b8934198e0..8d95d7c334e453fab2592ffd227524f782985aff 100644
--- a/restrict_ip.services.yml
+++ b/restrict_ip.services.yml
@@ -31,6 +31,7 @@ services:
       - '@module_handler'
       - '@url_generator'
       - '@messenger'
+      - '@current_route_match'
 
     tags:
       - {name: event_subscriber}
diff --git a/src/EventSubscriber/RestrictIpEventSubscriber.php b/src/EventSubscriber/RestrictIpEventSubscriber.php
index 6bc282a417023ee5f6d6cc8513f60afc84106466..f080b9c2f6ee82ecc1a5976db3d20ee48b9edced 100644
--- a/src/EventSubscriber/RestrictIpEventSubscriber.php
+++ b/src/EventSubscriber/RestrictIpEventSubscriber.php
@@ -7,6 +7,7 @@ use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Logger\LoggerChannelFactoryInterface;
 use Drupal\Core\Messenger\Messenger;
+use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Routing\UrlGeneratorInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Core\Url;
@@ -15,6 +16,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpKernel\Event\RequestEvent;
+use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Symfony\Component\HttpKernel\KernelEvents;
 
 /**
@@ -38,6 +40,8 @@ class RestrictIpEventSubscriber implements EventSubscriberInterface, ContainerIn
    *   The Url Generator service.
    * @param \Drupal\Core\Messenger\Messenger $messenger
    *   The messenger service object.
+   * @param \Drupal\Core\Routing\RouteMatchInterface $routeMatch
+   *   The route match handler.
    */
   public function __construct(
     protected RestrictIpServiceInterface $restrictIpService,
@@ -46,6 +50,7 @@ class RestrictIpEventSubscriber implements EventSubscriberInterface, ContainerIn
     protected ModuleHandlerInterface $moduleHandler,
     protected UrlGeneratorInterface $urlGenerator,
     protected Messenger $messenger,
+    protected RouteMatchInterface $routeMatch,
   ) {
   }
 
@@ -60,6 +65,7 @@ class RestrictIpEventSubscriber implements EventSubscriberInterface, ContainerIn
       $container->get('module_handler'),
       $container->get('url_generator'),
       $container->get('messenger'),
+      $container->get('current_route_match'),
     );
   }
 
@@ -79,6 +85,11 @@ class RestrictIpEventSubscriber implements EventSubscriberInterface, ContainerIn
   public function checkIpRestricted(RequestEvent $event): void {
     unset($_SESSION['restrict_ip']);
 
+    // If we are on the system 403 route, bypass the inner logic.
+    if ($this->routeMatch->getRouteName() === 'system.403') {
+      return;
+    }
+
     $this->restrictIpService->testForBlock();
     $config = $this->configFactory->get('restrict_ip.settings');
     if ($this->restrictIpService->userIsBlocked()) {
@@ -95,6 +106,9 @@ class RestrictIpEventSubscriber implements EventSubscriberInterface, ContainerIn
           $url = Url::fromRoute('user.login');
           $event->setResponse(new RedirectResponse($url->toString()));
         }
+        elseif ($config->get('return_403')) {
+          throw new AccessDeniedHttpException();
+        }
         elseif (in_array($config->get('white_black_list'), [0, 1])) {
           $url = Url::fromRoute('restrict_ip.access_denied_page');
           $event->setResponse(new RedirectResponse($url->toString()));
diff --git a/src/Form/ConfigForm.php b/src/Form/ConfigForm.php
index 5dda5e66847a07b372194214b0a3717fba2731b9..7b54633285ab91d07ab1fa5a94c61dda5cf6651e 100644
--- a/src/Form/ConfigForm.php
+++ b/src/Form/ConfigForm.php
@@ -180,6 +180,21 @@ class ConfigForm extends ConfigFormBase {
       ],
     ];
 
+    $form['return_403'] = [
+      '#title' => $this->t('Return a 403 access denied response'),
+      '#type' => 'checkbox',
+      '#default_value' => $config->get('return_403'),
+      '#description' => $this->t('When this box is checked, a 403 access denied response will be returned instead of the access denied page or front page.'),
+      '#states' => [
+        'invisible' => [
+          [
+            '#edit-allow-role-bypass' => ['checked' => TRUE],
+            'input[name="bypass_action"]' => ['value' => 'redirect_login_page'],
+          ],
+        ],
+      ],
+    ];
+
     $form['white_black_list'] = [
       '#type' => 'radios',
       '#options' => [
@@ -394,6 +409,7 @@ class ConfigForm extends ConfigFormBase {
       ->set('dblog', (bool) $form_state->getValue('dblog'))
       ->set('allow_role_bypass', (bool) $form_state->getValue('allow_role_bypass'))
       ->set('bypass_action', (string) $form_state->getValue('bypass_action'))
+      ->set('return_403', (bool) $form_state->getValue('return_403'))
       ->set('white_black_list', (int) $form_state->getValue('white_black_list'))
       ->set('country_white_black_list', (int) $form_state->getValue('country_white_black_list'))
       ->set('country_list', $country_list)
diff --git a/tests/src/Functional/RestrictIpAccessTest.php b/tests/src/Functional/RestrictIpAccessTest.php
index 971877e3d5bae67c31930209e25a8f1816e6841a..85625bf317acb1fda23a65182cf01304adc9cb18 100644
--- a/tests/src/Functional/RestrictIpAccessTest.php
+++ b/tests/src/Functional/RestrictIpAccessTest.php
@@ -171,6 +171,27 @@ class RestrictIpAccessTest extends RestrictIpBrowserTestBase {
     $this->assertElementExists('#edit-name');
   }
 
+  /**
+   * Tests access denied response is returned when 'return_403' option enabled.
+   */
+  public function testAccessDeniedResponseWhenAccessDeniedOptionEnabled(): void {
+    $adminUser = $this->drupalCreateUser([
+      'administer restricted ip addresses',
+      'access administration pages',
+      'administer modules',
+    ]);
+
+    $this->drupalLogin($adminUser);
+    $this->drupalGet('admin/config/people/restrict_ip');
+    $this->assertStatusCodeEquals(200);
+
+    $this->checkCheckbox('#edit-enable');
+    $this->checkCheckbox('#edit-return-403');
+    $this->click('#edit-submit');
+
+    $this->assertStatusCodeEquals(403);
+  }
+
   /**
    * Tests whitelisting paths.
    *