diff --git a/doc/whats-new.rst b/doc/whats-new.rst
index 1f60d457432..44bff9e7202 100644
--- a/doc/whats-new.rst
+++ b/doc/whats-new.rst
@@ -47,6 +47,8 @@ Bug fixes
   By `Deepak Cherian <https://github.com/dcherian>`_.
 - Fix issue with Dask-backed datasets raising a ``KeyError`` on some computations involving ``map_blocks`` (:pull:`3598`)
   By `Tom Augspurger <https://github.com/TomAugspurger>`_.
+- Ensure :py:meth:`Dataset.quantile`, :py:meth:`DataArray.quantile` issue the correct error
+  when ``q`` is out of bounds (:issue:`3634`) by `Mathias Hauser <https://github.com/mathause>`_.
 
 Documentation
 ~~~~~~~~~~~~~
diff --git a/xarray/core/variable.py b/xarray/core/variable.py
index 17ecdf62730..4474d973f59 100644
--- a/xarray/core/variable.py
+++ b/xarray/core/variable.py
@@ -1731,6 +1731,10 @@ def quantile(self, q, dim=None, interpolation="linear", keep_attrs=None):
         scalar = utils.is_scalar(q)
         q = np.atleast_1d(np.asarray(q, dtype=np.float64))
 
+        # TODO: remove once numpy >= 1.15.0 is the minimum requirement
+        if np.count_nonzero(q < 0.0) or np.count_nonzero(q > 1.0):
+            raise ValueError("Quantiles must be in the range [0, 1]")
+
         if dim is None:
             dim = self.dims
 
@@ -1739,6 +1743,8 @@ def quantile(self, q, dim=None, interpolation="linear", keep_attrs=None):
 
         def _wrapper(npa, **kwargs):
             # move quantile axis to end. required for apply_ufunc
+
+            # TODO: use np.nanquantile once numpy >= 1.15.0 is the minimum requirement
             return np.moveaxis(np.nanpercentile(npa, **kwargs), 0, -1)
 
         axis = np.arange(-1, -1 * len(dim) - 1, -1)
diff --git a/xarray/tests/test_variable.py b/xarray/tests/test_variable.py
index 1d83e16a5bd..49a6906d5be 100644
--- a/xarray/tests/test_variable.py
+++ b/xarray/tests/test_variable.py
@@ -1542,6 +1542,14 @@ def test_quantile_chunked_dim_error(self):
         with raises_regex(ValueError, "dimension 'x'"):
             v.quantile(0.5, dim="x")
 
+    @pytest.mark.parametrize("q", [-0.1, 1.1, [2], [0.25, 2]])
+    def test_quantile_out_of_bounds(self, q):
+        v = Variable(["x", "y"], self.d)
+
+        # escape special characters
+        with raises_regex(ValueError, r"Quantiles must be in the range \[0, 1\]"):
+            v.quantile(q, dim="x")
+
     @requires_dask
     @requires_bottleneck
     def test_rank_dask_raises(self):