diff --git a/django/test/client.py b/django/test/client.py
index b26504f762..ce74a5fe53 100644
--- a/django/test/client.py
+++ b/django/test/client.py
@@ -826,8 +826,12 @@ class Client(ClientMixin, RequestFactory):
                 path = urljoin(response.request['PATH_INFO'], path)
 
             if response.status_code in (HTTPStatus.TEMPORARY_REDIRECT, HTTPStatus.PERMANENT_REDIRECT):
-                # Preserve request method post-redirect for 307/308 responses.
-                request_method = getattr(self, response.request['REQUEST_METHOD'].lower())
+                # Preserve request method and query string (if needed)
+                # post-redirect for 307/308 responses.
+                request_method = response.request['REQUEST_METHOD'].lower()
+                if request_method not in ('get', 'head'):
+                    extra['QUERY_STRING'] = url.query
+                request_method = getattr(self, request_method)
             else:
                 request_method = self.get
                 data = QueryDict(url.query)
diff --git a/docs/releases/3.2.txt b/docs/releases/3.2.txt
index 2d49299440..84f757cd2b 100644
--- a/docs/releases/3.2.txt
+++ b/docs/releases/3.2.txt
@@ -214,6 +214,9 @@ Tests
   creating deep copies with :py:func:`copy.deepcopy`. Assigning objects which
   don't support ``deepcopy()`` is deprecated and will be removed in Django 4.1.
 
+* :class:`~django.test.Client` now preserves the request query string when
+  following 307 and 308 redirects.
+
 URLs
 ~~~~
 
diff --git a/tests/test_client/tests.py b/tests/test_client/tests.py
index 0b63a3fed5..03bb658952 100644
--- a/tests/test_client/tests.py
+++ b/tests/test_client/tests.py
@@ -284,6 +284,20 @@ class ClientTest(TestCase):
                 self.assertEqual(response.request['PATH_INFO'], '/post_view/')
                 self.assertEqual(response.request['REQUEST_METHOD'], method.upper())
 
+    def test_follow_307_and_308_preserves_query_string(self):
+        methods = ('post', 'options', 'put', 'patch', 'delete', 'trace')
+        codes = (307, 308)
+        for method, code in itertools.product(methods, codes):
+            with self.subTest(method=method, code=code):
+                req_method = getattr(self.client, method)
+                response = req_method(
+                    '/redirect_view_%s_query_string/' % code,
+                    data={'value': 'test'},
+                    follow=True,
+                )
+                self.assertRedirects(response, '/post_view/?hello=world', status_code=code)
+                self.assertEqual(response.request['QUERY_STRING'], 'hello=world')
+
     def test_follow_307_and_308_get_head_query_string(self):
         methods = ('get', 'head')
         codes = (307, 308)