diff --git a/tests/regressiontests/admin_views/admin.py b/tests/regressiontests/admin_views/admin.py
--- a/tests/regressiontests/admin_views/admin.py
+++ b/tests/regressiontests/admin_views/admin.py
@@ -24,7 +24,7 @@
     CoverLetter, Story, OtherStory, Book, Promo, ChapterXtra1, Pizza, Topping,
     Album, Question, Answer, ComplexSortedPerson, PrePopulatedPostLargeSlug,
     AdminOrderedField, AdminOrderedModelMethod, AdminOrderedAdminMethod,
-    AdminOrderedCallable)
+    AdminOrderedCallable, Report)
 
 
 def callable_year(dt_value):
@@ -499,6 +499,9 @@
     ordering = ('order',)
     list_display = ('stuff', admin_ordered_callable)
 
+class ReportAdmin(admin.ModelAdmin):
+    def has_add_permission(self, request):
+        return False
 
 site = admin.AdminSite(name="admin")
 site.register(Article, ArticleAdmin)
@@ -543,6 +546,7 @@
 site.register(CoverLetter, CoverLetterAdmin)
 site.register(Story, StoryAdmin)
 site.register(OtherStory, OtherStoryAdmin)
+site.register(Report, ReportAdmin)
 
 # We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.
 # That way we cover all four cases:
diff --git a/tests/regressiontests/admin_views/models.py b/tests/regressiontests/admin_views/models.py
--- a/tests/regressiontests/admin_views/models.py
+++ b/tests/regressiontests/admin_views/models.py
@@ -566,3 +566,9 @@
 class AdminOrderedCallable(models.Model):
     order = models.IntegerField()
     stuff = models.CharField(max_length=200)
+
+class Report(models.Model):
+    title = models.CharField(max_length=100)
+
+    def __unicode__(self):
+        return self.title
diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py
--- a/tests/regressiontests/admin_views/tests.py
+++ b/tests/regressiontests/admin_views/tests.py
@@ -38,7 +38,8 @@
     Book, Promo, WorkHour, Employee, Question, Answer, Inquisition, Actor,
     FoodDelivery, RowLevelChangePermissionModel, Paper, CoverLetter, Story,
     OtherStory, ComplexSortedPerson, Parent, Child, AdminOrderedField,
-    AdminOrderedModelMethod, AdminOrderedAdminMethod, AdminOrderedCallable)
+    AdminOrderedModelMethod, AdminOrderedAdminMethod, AdminOrderedCallable,
+    Report)
 
 
 ERROR_MESSAGE = "Please enter the correct username and password \
@@ -1090,6 +1091,40 @@
         self.assertContains(response, 'id="login-form"')
 
 
+class AdminViewsNoPermissionsTest(TestCase):
+    """Regression test for #17333"""
+
+    urls = "regressiontests.admin_views.urls"
+    fixtures = ['admin-views-users.xml']
+
+    def setUp(self):
+        opts = Report._meta
+
+        # Programmatically remove add and change perms from on the Report model
+        # that syncdb should have created for us
+        #get_perm(Report, opts.get_add_permission()).delete()
+        #get_perm(Report, opts.get_change_permission()).delete()
+
+        # User who can change Reports
+        change_user = User.objects.get(username='changeuser')
+        change_user.user_permissions.add(get_perm(Report,
+            opts.get_change_permission()))
+
+        # login POST dict
+        self.changeuser_login = {
+            REDIRECT_FIELD_NAME: '/test_admin/admin/',
+            LOGIN_FORM_KEY: 1,
+            'username': 'changeuser',
+            'password': 'secret',
+        }
+
+    def test_no_add_perms(self):
+        self.client.get('/test_admin/admin/')
+        self.client.post('/test_admin/admin/', self.changeuser_login)
+        r = self.client.get('/test_admin/admin/')
+        self.assertEqual(r.status_code, 200)
+        self.client.get('/test_admin/admin/logout/')
+
 class AdminViewDeletedObjectsTest(TestCase):
     urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-users.xml', 'deleted-objects.xml']
