diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py
index c23aa5cf4fd5..0bdb8ce5a854 100644
--- a/lib/matplotlib/colorbar.py
+++ b/lib/matplotlib/colorbar.py
@@ -422,6 +422,7 @@ def __init__(self, ax, cmap=None,
                  extend=None,
                  spacing='uniform',  # uniform or proportional
                  ticks=None,
+                 ticklabels=None,
                  format=None,
                  drawedges=False,
                  filled=True,
@@ -463,6 +464,8 @@ def __init__(self, ax, cmap=None,
              'min': slice(1, None), 'max': slice(0, -1)},
             extend=extend)
         self.spacing = spacing
+        self._ticks = ticks
+        self._ticklabels = ticklabels
         self.orientation = orientation
         self.drawedges = drawedges
         self.filled = filled
@@ -543,6 +546,8 @@ def draw_all(self):
         self.outline.set_xy(xy)
         self.patch.set_xy(xy)
         self.update_ticks()
+        if self._ticklabels:
+            self.set_ticklabels(self._ticklabels)
         if self.filled:
             self._add_solids(X, Y, self._values[:, np.newaxis])
 
@@ -688,14 +693,19 @@ def set_ticks(self, ticks, update_ticks=True):
             user has to call `update_ticks` later to update the ticks.
 
         """
-        if np.iterable(ticks):
-            self.locator = ticker.FixedLocator(ticks, nbins=len(ticks))
+        if np.iterable(ticks) or isinstance(ticks, ticker.Locator):
+            self._ticks = ticks  # self._ticks always holds a valid value
+            if np.iterable(ticks):
+                self.locator = ticker.FixedLocator(ticks, nbins=len(ticks))
+            else:
+                self.locator = ticks
+            if update_ticks:
+                self.update_ticks()
+                self._ticks = self.get_ticks()
+            self.stale = True
         else:
-            self.locator = ticks
-
-        if update_ticks:
-            self.update_ticks()
-        self.stale = True
+            cbook._warn_external('The ticks need to be an array of values '
+                                 'or an instance of ticker.Locator')
 
     def get_ticks(self, minor=False):
         """Return the x ticks as a list of locations."""
@@ -716,12 +726,28 @@ def set_ticklabels(self, ticklabels, update_ticks=True):
         Tick labels are updated immediately unless *update_ticks* is *False*,
         in which case one should call `.update_ticks` explicitly.
         """
-        if isinstance(self.locator, ticker.FixedLocator):
+        # check if explitic ticks have been supplied
+        if self._ticks is None:
+            cbook._warn_external('To set explicit ticklabels, call colorbar() '
+                                 'with ticks keyword or use set_ticks() '
+                                 'method first.')
+        # check if length of ticks and ticklabels match
+        elif len(self._ticks) != len(self._ticklabels):
+            cbook._warn_external('The ticklabels need to be of the same '
+                                 'length as the ticks.')
+        # check if objects in list have valid type
+        elif not all(type(item) in [str, float, int] for item in ticklabels):
+            cbook._warn_external('ticklabels need to be a list of str')
+        # this check was in the code previously, not sure if needed
+        elif isinstance(self.locator, ticker.FixedLocator):
             self.formatter = ticker.FixedFormatter(ticklabels)
             if update_ticks:
                 self.update_ticks()
         else:
-            cbook._warn_external("set_ticks() must have been called.")
+            cbook._warn_external('To set ticklabels, ticks of the same '
+                                 'length need to be set explicitly first. '
+                                 'This can be done through '
+                                 'plt.colorbar(ticks) or set_ticks().')
         self.stale = True
 
     def minorticks_on(self):
diff --git a/lib/matplotlib/tests/test_colorbar.py b/lib/matplotlib/tests/test_colorbar.py
index bbd1e9c5f590..f5a3d0fb4ec7 100644
--- a/lib/matplotlib/tests/test_colorbar.py
+++ b/lib/matplotlib/tests/test_colorbar.py
@@ -705,3 +705,36 @@ def test_anchored_cbar_position_using_specgrid():
     np.testing.assert_allclose(
             [cx1, cx0],
             [x1 * shrink + (1 - shrink) * p0, p0 * (1 - shrink) + x0 * shrink])
+
+
+def test_colorbar_ticklabels_2():
+    fig = plt.figure()
+    plt.imshow(np.arange(100).reshape((10, 10)))
+    ticklabels = ['cat', 'dog']
+    cbar = plt.colorbar(ticks=[10, 90], ticklabels=ticklabels)
+    fig.canvas.draw()
+    for i, item in enumerate(cbar.ax.yaxis.get_ticklabels()):
+        assert ticklabels[i] == item.get_text()
+
+
+def test_colorbar_ticklabels_3():
+    fig = plt.figure()
+    plt.imshow(np.arange(100).reshape((10, 10)))
+    ticklabels = ['cat', 'dog', 'elephant']
+    with pytest.warns(
+            UserWarning, match='The ticklabels need to be of the same '
+            'length as the ticks.'):
+        plt.colorbar(ticks=[10, 90], ticklabels=ticklabels)
+        fig.canvas.draw()
+
+
+def test_colorbar_ticklabels_no_ticks():
+    fig = plt.figure()
+    plt.imshow(np.arange(100).reshape((10, 10)))
+    ticklabels = ['cat', 'dog', 'dog']
+    with pytest.warns(
+            UserWarning, match='To set explicit ticklabels, call colorbar'
+            '\\(\\) with ticks keyword or use set_ticks\\(\\) '
+            'method first.'):
+        plt.colorbar(ticks=None, ticklabels=ticklabels)
+        fig.canvas.draw()
diff --git a/lib/mpl_toolkits/axes_grid1/colorbar.py b/lib/mpl_toolkits/axes_grid1/colorbar.py
index 77af5a1ab7fc..182dcaf9a6d1 100644
--- a/lib/mpl_toolkits/axes_grid1/colorbar.py
+++ b/lib/mpl_toolkits/axes_grid1/colorbar.py
@@ -55,30 +55,33 @@
 
 colormap_kw_doc = '''
 
-    ===========   ====================================================
-    Property      Description
-    ===========   ====================================================
-    *extend*      [ 'neither' | 'both' | 'min' | 'max' ]
-                  If not 'neither', make pointed end(s) for out-of-
-                  range values.  These are set for a given colormap
-                  using the colormap set_under and set_over methods.
-    *spacing*     [ 'uniform' | 'proportional' ]
-                  Uniform spacing gives each discrete color the same
-                  space; proportional makes the space proportional to
-                  the data interval.
-    *ticks*       [ None | list of ticks | Locator object ]
-                  If None, ticks are determined automatically from the
-                  input.
-    *format*      [ None | format string | Formatter object ]
-                  If None, the
-                  :class:`~matplotlib.ticker.ScalarFormatter` is used.
-                  If a format string is given, e.g., '%.3f', that is
-                  used. An alternative
-                  :class:`~matplotlib.ticker.Formatter` object may be
-                  given instead.
-    *drawedges*   bool
-                  Whether to draw lines at color boundaries.
-    ===========   ====================================================
+    ============   ====================================================
+    Property       Description
+    ============   ====================================================
+    *extend*       [ 'neither' | 'both' | 'min' | 'max' ]
+                   If not 'neither', make pointed end(s) for out-of-
+                   range values.  These are set for a given colormap
+                   using the colormap set_under and set_over methods.
+    *spacing*      [ 'uniform' | 'proportional' ]
+                   Uniform spacing gives each discrete color the same
+                   space; proportional makes the space proportional to
+                   the data interval.
+    *ticks*        [ None | list of ticks | Locator object ]
+                   If None, ticks are determined automatically from the
+                   input.
+    *ticklabels*   sequence of str
+                   List of texts for tick labels; must include values
+                   for non-visible labels.
+    *format*       [ None | format string | Formatter object ]
+                   If None, the
+                   :class:`~matplotlib.ticker.ScalarFormatter` is used.
+                   If a format string is given, e.g., '%.3f', that is
+                   used. An alternative
+                   :class:`~matplotlib.ticker.Formatter` object may be
+                   given instead.
+    *drawedges*    bool
+                   Whether to draw lines at color boundaries.
+    ============   ====================================================
 
     The following will probably be useful only in the context of
     indexed colors (that is, when the mappable has norm=NoNorm()),