diff --git a/reviewboard/accounts/backends/nis.py b/reviewboard/accounts/backends/nis.py
index 371c876c7a42c56d214053c8224009c420f4e9c3..21d98b9f34312a27007ea86a5f9299d45a8fc115 100644
--- a/reviewboard/accounts/backends/nis.py
+++ b/reviewboard/accounts/backends/nis.py
@@ -1,13 +1,24 @@
 """NIS authentication backend."""
 
+from __future__ import annotations
+
+import logging
+from importlib import import_module
+from types import ModuleType
+from typing import Optional
+
 from django.conf import settings
 from django.contrib.auth.models import User
+from django.utils.functional import cached_property
 from django.utils.translation import gettext_lazy as _
 
 from reviewboard.accounts.backends.base import BaseAuthBackend
 from reviewboard.accounts.forms.auth import NISSettingsForm
 
 
+logger = logging.getLogger(__name__)
+
+
 class NISBackend(BaseAuthBackend):
     """Authenticate against a user on an NIS server."""
 
@@ -17,6 +28,26 @@ class NISBackend(BaseAuthBackend):
     login_instructions = \
         _('Use your standard NIS username and password.')
 
+    @cached_property
+    def nis(self) -> Optional[ModuleType]:
+        """The nis module, used for interacting with NIS.
+
+        On first access, this will check if NIS is available, logging an
+        error if missing.
+
+        This safeguards against Python environments without NIS, and against
+        versions of Python >= 3.13.
+
+        Type:
+            module
+        """
+        try:
+            return import_module('nis')
+        except ImportError:
+            logger.error('The nis module is not available on your version '
+                         'of Python.')
+            return None
+
     def authenticate(self, request, username, password, **kwargs):
         """Authenticate the user.
 
@@ -47,11 +78,15 @@ class NISBackend(BaseAuthBackend):
             The authenticated user, or ``None`` if the user could not be
             authenticated.
         """
-        import crypt
-        import nis
+        nis = self.nis
+
+        if nis is None:
+            return None
 
         username = username.strip()
 
+        import crypt
+
         try:
             passwd = self._nis_get_passwd(username)
         except nis.error:
@@ -87,7 +122,10 @@ class NISBackend(BaseAuthBackend):
             The existing or newly-created user, or ``None`` if an error was
             encountered.
         """
-        import nis
+        nis = self.nis
+
+        if nis is None:
+            return None
 
         username = username.strip()
 
diff --git a/reviewboard/accounts/tests/test_nis_auth_backend.py b/reviewboard/accounts/tests/test_nis_auth_backend.py
index 3f281c8f6d70b7bf5a139b595110b56836fbf4fe..1432d63af76f3ff139d71e107f5694b7c82556fb 100644
--- a/reviewboard/accounts/tests/test_nis_auth_backend.py
+++ b/reviewboard/accounts/tests/test_nis_auth_backend.py
@@ -1,6 +1,6 @@
 """Unit tests for NISBackend."""
 
-import nis
+from unittest import SkipTest
 
 from django.contrib.auth.models import User
 from kgb import SpyAgency
@@ -21,6 +21,9 @@ class NISBackendTests(SpyAgency, TestCase):
 
         self.backend = NISBackend()
 
+        if self.backend.nis is None:
+            raise SkipTest('nis is not available on this build of Python.')
+
     def test_authenticate_with_valid_user(self):
         """Testing NISBackend.authenticate with valid user credentials"""
         self.spy_on(self.backend._nis_get_passwd, lambda _self, username: (
