diff --git a/Tests/test_imagegrab.py b/Tests/test_imagegrab.py
index 180682c6415..791628142de 100644
--- a/Tests/test_imagegrab.py
+++ b/Tests/test_imagegrab.py
@@ -25,8 +25,15 @@ def test_grab(self) -> None:
         ImageGrab.grab(include_layered_windows=True)
         ImageGrab.grab(all_screens=True)
 
-        im = ImageGrab.grab(bbox=(10, 20, 50, 80))
-        assert im.size == (40, 60)
+        if sys.platform == "darwin":
+            im = ImageGrab.grab(bbox=(10, 20, 50, 80))
+            assert im.size in ((40, 60), (80, 120))
+
+            im = ImageGrab.grab(bbox=(10, 20, 50, 80), scale_down=True)
+            assert im.size == (40, 60)
+        else:
+            im = ImageGrab.grab(bbox=(10, 20, 50, 80))
+            assert im.size == (40, 60)
 
     @skip_unless_feature("xcb")
     def test_grab_x11(self) -> None:
@@ -81,7 +88,7 @@ def test_grab_handle(self) -> None:
 
         ImageGrab.grab(window=window)
 
-        im = ImageGrab.grab((0, 0, 10, 10), window=window)
+        im = ImageGrab.grab((0, 0, 10, 10), window=window, scale_down=True)
         assert im.size == (10, 10)
 
     @pytest.mark.skipif(
diff --git a/docs/reference/ImageGrab.rst b/docs/reference/ImageGrab.rst
index 4138667850b..d358cf53d4b 100644
--- a/docs/reference/ImageGrab.rst
+++ b/docs/reference/ImageGrab.rst
@@ -9,11 +9,14 @@ or the clipboard to a PIL image memory.
 
 .. versionadded:: 1.1.3
 
-.. py:function:: grab(bbox=None, include_layered_windows=False, all_screens=False, xdisplay=None, window=None)
+.. py:function:: grab(bbox=None, include_layered_windows=False, all_screens=False, xdisplay=None, window=None, scale_down=False)
 
     Take a snapshot of the screen. The pixels inside the bounding box are returned as
-    an "RGBA" on macOS, or an "RGB" image otherwise. If the bounding box is omitted,
-    the entire screen is copied, and on macOS, it will be at 2x if on a Retina screen.
+    "RGBA" on macOS, or "RGB" image otherwise. If the bounding box is omitted,
+    the entire screen is copied.
+
+    On macOS, it will be at 2x if on a Retina screen. If this is not desired, pass
+    ``scale_down=True``.
 
     On Linux, if ``xdisplay`` is ``None`` and the default X11 display does not return
     a snapshot of the screen, ``gnome-screenshot``, ``grim`` or ``spectacle`` will be
@@ -25,8 +28,8 @@ or the clipboard to a PIL image memory.
     .. versionadded:: 7.1.0 Linux support
 
     :param bbox: What region to copy. Default is the entire screen.
-                 On macOS, this is not increased to 2x for Retina screens, so the full
-                 width of a Retina screen would be 1440, not 2880.
+                 On macOS, this is increased to 2x for Retina screens, so the full
+                 width of a Retina screen would be 2880, not 1440.
                  On Windows, the top-left point may be negative if ``all_screens=True``
                  is used.
     :param include_layered_windows: Includes layered windows. Windows OS only.
@@ -49,6 +52,11 @@ or the clipboard to a PIL image memory.
 
         .. versionadded:: 11.2.1 Windows support
         .. versionadded:: 12.1.0 macOS support
+
+    :param scale_down: On macOS, Retina screens will provide ``bbox`` images at 2x size by default. This will prevent that, and scale down to 1x.
+                       Keyword-only argument.
+
+        .. versionadded:: 12.3.0
     :return: An image
 
 .. py:function:: grabclipboard()
diff --git a/docs/releasenotes/12.3.0.rst b/docs/releasenotes/12.3.0.rst
index 58c8836d278..b6ff05ffad8 100644
--- a/docs/releasenotes/12.3.0.rst
+++ b/docs/releasenotes/12.3.0.rst
@@ -41,10 +41,15 @@ TODO
 API additions
 =============
 
-TODO
-^^^^
+Added ``scale_down`` argument to ``ImageGrab.grab()``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-TODO
+:py:meth:`~PIL.ImageGrab.grab` now accepts an optional keyword argument of
+``scale_down``. This affects macOS screenshots with a ``bbox`` on a Retina screen. By
+default, images will be captured at 2x. If ``scale_down`` is ``True``, they will be at
+1x.
+
+Previously, macOS screenshots with a ``bbox`` were captured at 1x by default.
 
 Other changes
 =============
diff --git a/src/PIL/ImageGrab.py b/src/PIL/ImageGrab.py
index 66ee6dd33a3..52cbfea406d 100644
--- a/src/PIL/ImageGrab.py
+++ b/src/PIL/ImageGrab.py
@@ -36,6 +36,8 @@ def grab(
     all_screens: bool = False,
     xdisplay: str | None = None,
     window: int | ImageWin.HWND | None = None,
+    *,
+    scale_down: bool = False,
 ) -> Image.Image:
     im: Image.Image
     if xdisplay is None:
@@ -74,15 +76,16 @@ def grab(
                     # crop the image manually
                     if retina:
                         left, top, right, bottom = bbox
+                        scale = 1 if scale_down else 2
                         im_cropped = im.resize(
-                            (right - left, bottom - top),
+                            ((right - left) * scale, (bottom - top) * scale),
                             box=tuple(coord * 2 for coord in bbox),
                         )
                     else:
                         im_cropped = im.crop(bbox)
                     im.close()
                     return im_cropped
-                else:
+                elif scale_down:
                     im_resized = im.resize((right - left, bottom - top))
                     im.close()
                     return im_resized
