diff --git a/common/djangoapps/student/tests/test_reset_password.py b/common/djangoapps/student/tests/test_reset_password.py
index cb9c0ee0753381b5ca1775599f4324df9af0ab05..6601553c700c7351d6d1dc95c2059bdde19fe9be 100644
--- a/common/djangoapps/student/tests/test_reset_password.py
+++ b/common/djangoapps/student/tests/test_reset_password.py
@@ -3,11 +3,12 @@ Test the various password reset flows
 """
 import json
 import re
+import unicodedata
 import unittest
 
 import ddt
 from django.conf import settings
-from django.contrib.auth.hashers import UNUSABLE_PASSWORD_PREFIX
+from django.contrib.auth.hashers import UNUSABLE_PASSWORD_PREFIX, make_password
 from django.contrib.auth.models import User
 from django.contrib.auth.tokens import default_token_generator
 from django.core.cache import cache
@@ -24,7 +25,9 @@ from provider.oauth2 import models as dop_models
 from openedx.core.djangoapps.oauth_dispatch.tests import factories as dot_factories
 from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
 from openedx.core.djangoapps.user_api.models import UserRetirementRequest
-from openedx.core.djangoapps.user_api.config.waffle import PREVENT_AUTH_USER_WRITES, SYSTEM_MAINTENANCE_MSG, waffle
+from openedx.core.djangoapps.user_api.config.waffle import (
+    PASSWORD_UNICODE_NORMALIZE_FLAG, PREVENT_AUTH_USER_WRITES, SYSTEM_MAINTENANCE_MSG, waffle
+)
 from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
 from student.tests.factories import UserFactory
 from student.tests.test_email import mock_render_to_string
@@ -351,6 +354,28 @@ class ResetPasswordTests(EventTestMixin, CacheIsolationTestCase):
                 self.user.refresh_from_db()
                 assert not self.user.is_active
 
+    def test_password_reset_normalize_password(self):
+        """
+        Tests that if we provide a not properly normalized password, it is saved using our normalization
+        method of NFKC.
+        In this test, the input password is u'p\u212bssword'. It should be normalized to u'p\xc5ssword'
+        """
+        with PASSWORD_UNICODE_NORMALIZE_FLAG.override(active=True):
+            url = reverse(
+                "password_reset_confirm",
+                kwargs={"uidb36": self.uidb36, "token": self.token}
+            )
+
+            password = u'p\u212bssword'
+            request_params = {'new_password1': password, 'new_password2': password}
+            confirm_request = self.request_factory.post(url, data=request_params)
+            response = password_reset_confirm_wrapper(confirm_request, self.uidb36, self.token)
+
+            user = User.objects.get(pk=self.user.pk)
+            salt_val = user.password.split('$')[1]
+            expected_user_password = make_password(unicodedata.normalize('NFKC', u'p\u212bssword'), salt_val)
+            self.assertEqual(expected_user_password, user.password)
+
     @override_settings(AUTH_PASSWORD_VALIDATORS=[
         create_validator_config('util.password_policy_validators.MinimumLengthValidator', {'min_length': 2}),
         create_validator_config('util.password_policy_validators.MaximumLengthValidator', {'max_length': 10})
diff --git a/common/djangoapps/student/views/management.py b/common/djangoapps/student/views/management.py
index 8652adceda843ccf2138e81d2980c931d6aa7c64..217ffec4a915fdb7b6e2b3c8c4ddd6e447b25f8d 100644
--- a/common/djangoapps/student/views/management.py
+++ b/common/djangoapps/student/views/management.py
@@ -57,7 +57,9 @@ from openedx.core.djangoapps.programs.models import ProgramsApiConfig
 from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
 from openedx.core.djangoapps.theming import helpers as theming_helpers
 from openedx.core.djangoapps.theming.helpers import get_current_site
-from openedx.core.djangoapps.user_api.config.waffle import PREVENT_AUTH_USER_WRITES, SYSTEM_MAINTENANCE_MSG, waffle
+from openedx.core.djangoapps.user_api.config.waffle import (
+    PASSWORD_UNICODE_NORMALIZE_FLAG, PREVENT_AUTH_USER_WRITES, SYSTEM_MAINTENANCE_MSG, waffle
+)
 from openedx.core.djangoapps.user_api.errors import UserNotFound, UserAPIInternalError
 from openedx.core.djangoapps.user_api.models import UserRetirementRequest
 from openedx.core.djangoapps.user_api.preferences import api as preferences_api
@@ -94,7 +96,7 @@ from student.text_me_the_app import TextMeTheAppFragmentView
 from util.bad_request_rate_limiter import BadRequestRateLimiter
 from util.db import outer_atomic
 from util.json_request import JsonResponse
-from util.password_policy_validators import validate_password
+from util.password_policy_validators import normalize_password, validate_password
 
 log = logging.getLogger("edx.student")
 
@@ -827,6 +829,17 @@ def password_reset_confirm_wrapper(request, uidb36=None, token=None):
         )
 
     if request.method == 'POST':
+        if PASSWORD_UNICODE_NORMALIZE_FLAG.is_enabled():
+            # We have to make a copy of request.POST because it is a QueryDict object which is immutable until copied.
+            # We have to use request.POST because the password_reset_confirm method takes in the request and a user's
+            # password is set to the request.POST['new_password1'] field. We have to also normalize the new_password2
+            # field so it passes the equivalence check that new_password1 == new_password2
+            # In order to switch out of having to do this copy, we would want to move the normalize_password code into
+            # a custom User model's set_password method to ensure it is always happening upon calling set_password.
+            request.POST = request.POST.copy()
+            request.POST['new_password1'] = normalize_password(request.POST['new_password1'])
+            request.POST['new_password2'] = normalize_password(request.POST['new_password2'])
+
         password = request.POST['new_password1']
 
         try: