diff --git a/cms/envs/common.py b/cms/envs/common.py
index 04c8ee5e5202b3c676c9413a6afe1f086d7cc7ad..746f08a5aecfc961a9b99efd567611f8a5bfa618 100644
--- a/cms/envs/common.py
+++ b/cms/envs/common.py
@@ -2340,6 +2340,9 @@ DISABLE_DEPRECATED_SIGNUP_URL = False
 LOGISTRATION_RATELIMIT_RATE = '100/5m'
 LOGISTRATION_PER_EMAIL_RATELIMIT_RATE = '30/5m'
 LOGISTRATION_API_RATELIMIT = '20/m'
+RESET_PASSWORD_TOKEN_VALIDATE_API_RATELIMIT = '30/7d'
+RESET_PASSWORD_API_RATELIMIT = '30/7d'
+
 
 ##### REGISTRATION RATE LIMIT SETTINGS #####
 REGISTRATION_VALIDATION_RATELIMIT = '30/7d'
diff --git a/cms/envs/test.py b/cms/envs/test.py
index 4fd06839f47209e18f9cef302fefb41c25e1b4b6..09c9919a35eaf60b1fb8cd22cd2528ba45295543 100644
--- a/cms/envs/test.py
+++ b/cms/envs/test.py
@@ -331,7 +331,8 @@ LOGISTRATION_PER_EMAIL_RATELIMIT_RATE = '6/5m'
 LOGISTRATION_API_RATELIMIT = '5/m'
 
 REGISTRATION_VALIDATION_RATELIMIT = '5/minute'
-
+RESET_PASSWORD_TOKEN_VALIDATE_API_RATELIMIT = '2/m'
+RESET_PASSWORD_API_RATELIMIT = '2/m'
 # Don't tolerate deprecated edx-platform import usage in tests.
 ERROR_ON_DEPRECATED_EDX_PLATFORM_IMPORTS = True
 
diff --git a/lms/envs/common.py b/lms/envs/common.py
index 91fa13247caf8e673c391a3b6b89925b78a0cfa4..8dcd607b537eb1b0508058e6cebbb052d6a4c4d8 100644
--- a/lms/envs/common.py
+++ b/lms/envs/common.py
@@ -4370,6 +4370,8 @@ RATELIMIT_RATE = '120/m'
 LOGISTRATION_RATELIMIT_RATE = '100/5m'
 LOGISTRATION_PER_EMAIL_RATELIMIT_RATE = '30/5m'
 LOGISTRATION_API_RATELIMIT = '20/m'
+RESET_PASSWORD_TOKEN_VALIDATE_API_RATELIMIT = '30/7d'
+RESET_PASSWORD_API_RATELIMIT = '30/7d'
 
 ##### PASSWORD RESET RATE LIMIT SETTINGS #####
 PASSWORD_RESET_IP_RATE = '1/m'
diff --git a/lms/envs/production.py b/lms/envs/production.py
index f0b3ed5635109ad65c718f08c672bc0570f5df78..f76f774f68de87dd37ab4171526ffc962580e9fd 100644
--- a/lms/envs/production.py
+++ b/lms/envs/production.py
@@ -605,6 +605,10 @@ MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS = ENV_TOKENS.get(
 ##### LOGISTRATION RATE LIMIT SETTINGS #####
 LOGISTRATION_RATELIMIT_RATE = ENV_TOKENS.get('LOGISTRATION_RATELIMIT_RATE', LOGISTRATION_RATELIMIT_RATE)
 LOGISTRATION_API_RATELIMIT = ENV_TOKENS.get('LOGISTRATION_API_RATELIMIT', LOGISTRATION_API_RATELIMIT)
+RESET_PASSWORD_TOKEN_VALIDATE_API_RATELIMIT = ENV_TOKENS.get(
+    'RESET_PASSWORD_TOKEN_VALIDATE_API_RATELIMIT', RESET_PASSWORD_TOKEN_VALIDATE_API_RATELIMIT
+)
+RESET_PASSWORD_API_RATELIMIT = ENV_TOKENS.get('RESET_PASSWORD_API_RATELIMIT', RESET_PASSWORD_API_RATELIMIT)
 
 ##### REGISTRATION RATE LIMIT SETTINGS #####
 REGISTRATION_VALIDATION_RATELIMIT = ENV_TOKENS.get(
diff --git a/lms/envs/test.py b/lms/envs/test.py
index f3f1d3974b4fe2d7755802fb5b22040d9e2bd637..47583c8d0fee00373b1edfc756f5d2c76dd8029c 100644
--- a/lms/envs/test.py
+++ b/lms/envs/test.py
@@ -599,6 +599,8 @@ LOGISTRATION_PER_EMAIL_RATELIMIT_RATE = '6/5m'
 LOGISTRATION_API_RATELIMIT = '5/m'
 
 REGISTRATION_VALIDATION_RATELIMIT = '5/minute'
+RESET_PASSWORD_TOKEN_VALIDATE_API_RATELIMIT = '2/m'
+RESET_PASSWORD_API_RATELIMIT = '2/m'
 
 # Don't tolerate deprecated edx-platform import usage in tests.
 ERROR_ON_DEPRECATED_EDX_PLATFORM_IMPORTS = True
diff --git a/openedx/core/djangoapps/user_authn/views/password_reset.py b/openedx/core/djangoapps/user_authn/views/password_reset.py
index bf6c9da8b9813016beda31a6265d24ec33348a1a..1f6b2dd42549110916d70bb2fb4d4f835838b9a9 100644
--- a/openedx/core/djangoapps/user_authn/views/password_reset.py
+++ b/openedx/core/djangoapps/user_authn/views/password_reset.py
@@ -26,6 +26,7 @@ from edx_ace.recipient import Recipient
 from eventtracking import tracker
 from ratelimit.decorators import ratelimit
 from rest_framework.response import Response
+from rest_framework.throttling import AnonRateThrottle
 from rest_framework.views import APIView
 
 from common.djangoapps.edxmako.shortcuts import render_to_string
@@ -642,7 +643,35 @@ def password_change_request_handler(request):
         return HttpResponseBadRequest(_("No email address provided."))
 
 
+def _get_rate(rate):
+    """
+    Given the request rate string, return a two tuple of:
+    <allowed number of requests>, <period of time in seconds>
+    """
+
+    requests, duration = rate.split('/')
+    num_requests = int(requests)
+    num = int(duration[:-1] if duration[:-1] else 1)
+    symbol = duration[-1:]
+    duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[symbol] * num
+    return (num_requests, duration)
+
+
+class ResetTokenValidationThrottle(AnonRateThrottle):
+    """
+    Setting rate limit for token validation
+    """
+    rate = settings.RESET_PASSWORD_TOKEN_VALIDATE_API_RATELIMIT
+
+    def parse_rate(self, rate):
+        return _get_rate(rate)
+
+
 class PasswordResetTokenValidation(APIView):  # lint-amnesty, pylint: disable=missing-class-docstring
+    """
+    API to validate generated password reset token
+    """
+    throttle_classes = [ResetTokenValidationThrottle]
 
     def post(self, request):
         """ HTTP end-point to validate password reset token. """
@@ -668,7 +697,21 @@ class PasswordResetTokenValidation(APIView):  # lint-amnesty, pylint: disable=mi
         return Response({'is_valid': is_valid})
 
 
+class PasswordResetThrottle(AnonRateThrottle):
+    """
+    Setting rate limit for password reset
+    """
+    rate = settings.RESET_PASSWORD_API_RATELIMIT
+
+    def parse_rate(self, rate):
+        return _get_rate(rate)
+
+
 class LogistrationPasswordResetView(APIView):  # lint-amnesty, pylint: disable=missing-class-docstring
+    """
+    API to update new password credentials for a correct token
+    """
+    throttle_classes = [PasswordResetThrottle]
 
     def post(self, request, **kwargs):
         """ Reset learner password using passed token and new credentials """
diff --git a/openedx/core/djangoapps/user_authn/views/tests/test_reset_password.py b/openedx/core/djangoapps/user_authn/views/tests/test_reset_password.py
index 0f3798a2b7f32bd144a60ce6e3b4b39f15f6f98b..bce2154e562d1eef86d3951106d2022d518b7084 100644
--- a/openedx/core/djangoapps/user_authn/views/tests/test_reset_password.py
+++ b/openedx/core/djangoapps/user_authn/views/tests/test_reset_password.py
@@ -709,6 +709,24 @@ class PasswordResetTokenValidateViewTest(UserAPITestCase):
         self.user = User.objects.get(pk=self.user.pk)
         assert not self.user.is_active
 
+    @override_settings(
+        CACHES={
+            'default': {
+                'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
+                'LOCATION': 'validate_token',
+            }
+        }
+    )
+    def test_reset_password_token_api_throttle(self):
+        """
+        Test that the reset password token validation endpoint is throttling
+        """
+        for _ in range(int(settings.RESET_PASSWORD_TOKEN_VALIDATE_API_RATELIMIT.split('/')[0])):
+            response = self.client.post(self.url, data={'token': self.token})
+            assert response.status_code != 429
+        response = self.client.post(self.url, data={'token': self.token})
+        assert response.status_code == 429
+
 
 @ddt.ddt
 @unittest.skipUnless(
@@ -831,3 +849,26 @@ class ResetPasswordAPITests(EventTestMixin, CacheIsolationTestCase):
         assert sent_message.from_email == from_email
         assert len(sent_message.to) == 1
         assert updated_user.email in sent_message.to[0]
+
+    @override_settings(
+        CACHES={
+            'default': {
+                'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
+                'LOCATION': 'reset_password',
+            }
+        }
+    )
+    def test_password_reset_api_throttle(self):
+        """
+        Test that the reset password end point is throttling
+        """
+        path = reverse(
+            "logistration_password_reset",
+            kwargs={"uidb36": self.uidb36, "token": self.token}
+        )
+        request_param = {'new_password1': 'new_password1', 'new_password2': 'new_password1'}
+        for _ in range(int(settings.RESET_PASSWORD_API_RATELIMIT.split('/')[0])):
+            response = self.client.post(path, request_param)
+            assert response.status_code != 429
+        response = self.client.post(path, request_param)
+        assert response.status_code == 429