diff --git a/common/djangoapps/student/admin.py b/common/djangoapps/student/admin.py
index 9446a02249e102594a408e2616e385085322dd6b..2b102fdb1fd98f83419f1ead7cb42a07971d0201 100644
--- a/common/djangoapps/student/admin.py
+++ b/common/djangoapps/student/admin.py
@@ -5,6 +5,7 @@ from django.contrib import admin
 from django.contrib.admin.sites import NotRegistered
 from django.contrib.auth import get_user_model
 from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
+from django.db import models
 from django.utils.translation import ugettext_lazy as _
 from opaque_keys import InvalidKeyError
 from opaque_keys.edx.keys import CourseKey
@@ -181,6 +182,21 @@ class CourseEnrollmentAdmin(admin.ModelAdmin):
     search_fields = ('course__id', 'mode', 'user__username',)
     form = CourseEnrollmentForm
 
+    def get_search_results(self, request, queryset, search_term):
+        qs, use_distinct = super(CourseEnrollmentAdmin, self).get_search_results(request, queryset, search_term)
+
+        # annotate each enrollment with whether the username was an
+        # exact match for the search term
+        qs = qs.annotate(exact_username_match=models.Case(
+            models.When(user__username=search_term, then=models.Value(True)),
+            default=models.Value(False),
+            output_field=models.BooleanField()))
+
+        # present exact matches first
+        qs = qs.order_by('-exact_username_match', 'user__username', 'course_id')
+
+        return qs, use_distinct
+
     def queryset(self, request):
         return super(CourseEnrollmentAdmin, self).queryset(request).select_related('user')
 
diff --git a/common/djangoapps/student/tests/test_admin_views.py b/common/djangoapps/student/tests/test_admin_views.py
index 641d93439728058738fec527a9ea6ea7dd793d83..ef5d2cb882c34c2ad150df5aba06fcfc6c1f6f8c 100644
--- a/common/djangoapps/student/tests/test_admin_views.py
+++ b/common/djangoapps/student/tests/test_admin_views.py
@@ -208,11 +208,12 @@ class CourseEnrollmentAdminTest(SharedModuleStoreTestCase):
     def setUp(self):
         super(CourseEnrollmentAdminTest, self).setUp()
         self.user = UserFactory.create(is_staff=True, is_superuser=True)
-        self.client.login(username=self.user.username, password='test')
+        self.course = CourseFactory()
         CourseEnrollmentFactory(
             user=self.user,
-            course_id=CourseFactory().id,  # pylint: disable=no-member
+            course_id=self.course.id,  # pylint: disable=no-member
         )
+        self.client.login(username=self.user.username, password='test')
 
     @ddt.data(*ADMIN_URLS)
     @ddt.unpack
@@ -232,3 +233,24 @@ class CourseEnrollmentAdminTest(SharedModuleStoreTestCase):
         with COURSE_ENROLLMENT_ADMIN_SWITCH.override(active=True):
             response = getattr(self.client, method)(url)
         self.assertEqual(response.status_code, 200)
+
+    def test_username_exact_match(self):
+        """
+        Ensure that course enrollment searches return exact matches on username first.
+        """
+        user2 = UserFactory.create(username='aaa_{}'.format(self.user.username))
+        CourseEnrollmentFactory(
+            user=user2,
+            course_id=self.course.id,  # pylint: disable=no-member
+        )
+        search_url = '{}?q={}'.format(reverse('admin:student_courseenrollment_changelist'), self.user.username)
+        with COURSE_ENROLLMENT_ADMIN_SWITCH.override(active=True):
+            response = self.client.get(search_url)
+        self.assertEqual(response.status_code, 200)
+
+        # context['results'] is an array of arrays of HTML <td> elements to be rendered
+        self.assertEqual(len(response.context['results']), 2)
+        for idx, username in enumerate([self.user.username, user2.username]):
+            # Locate the <td> column containing the username
+            user_field = next(col for col in response.context['results'][idx] if "field-user" in col)
+            self.assertIn(username, user_field)