diff --git a/doc/source/command-objects/image.rst b/doc/source/command-objects/image.rst
index bc38429d9b..83036a64b7 100644
--- a/doc/source/command-objects/image.rst
+++ b/doc/source/command-objects/image.rst
@@ -141,6 +141,7 @@ List available images
         [--public | --private | --shared]
         [--property <key=value>]
         [--long]
+        [--sort <key>[:<direction>]]
 
 .. option:: --public
 
@@ -164,6 +165,11 @@ List available images
 
     List additional fields in output
 
+.. option:: --sort <key>[:<direction>]
+
+    Sort output by selected keys and directions(asc or desc) (default: asc),
+    multiple keys and directions can be specified separated by comma
+
 image save
 ----------
 
diff --git a/openstackclient/common/utils.py b/openstackclient/common/utils.py
index 9ad3823cc8..01a40e742b 100644
--- a/openstackclient/common/utils.py
+++ b/openstackclient/common/utils.py
@@ -122,6 +122,17 @@ def format_list(data):
     return ', '.join(sorted(data))
 
 
+def get_field(item, field):
+    try:
+        if isinstance(item, dict):
+            return item[field]
+        else:
+            return getattr(item, field)
+    except Exception:
+        msg = "Resource doesn't have field %s" % field
+        raise exceptions.CommandError(msg)
+
+
 def get_item_properties(item, fields, mixed_case_fields=[], formatters={}):
     """Return a tuple containing the item properties.
 
@@ -170,6 +181,35 @@ def get_dict_properties(item, fields, mixed_case_fields=[], formatters={}):
     return tuple(row)
 
 
+def sort_items(items, sort_str):
+    """Sort items based on sort keys and sort directions given by sort_str.
+
+    :param items: a list or generator object of items
+    :param sort_str: a string defining the sort rules, the format is
+    '<key1>:[direction1],<key2>:[direction2]...', direction can be 'asc'
+    for ascending or 'desc' for descending, if direction is not given,
+    it's ascending by default
+    :return: sorted items
+    """
+    if not sort_str:
+        return items
+    # items may be a generator object, transform it to a list
+    items = list(items)
+    sort_keys = sort_str.strip().split(',')
+    for sort_key in reversed(sort_keys):
+        reverse = False
+        if ':' in sort_key:
+            sort_key, direction = sort_key.split(':', 1)
+            if direction not in ['asc', 'desc']:
+                msg = "Specify sort direction by asc or desc"
+                raise exceptions.CommandError(msg)
+            if direction == 'desc':
+                reverse = True
+        items.sort(key=lambda item: get_field(item, sort_key),
+                   reverse=reverse)
+    return items
+
+
 def string_to_bool(arg):
     return arg.strip().lower() in ('t', 'true', 'yes', '1')
 
diff --git a/openstackclient/image/v1/image.py b/openstackclient/image/v1/image.py
index 2490d2a0c3..127a7735ec 100644
--- a/openstackclient/image/v1/image.py
+++ b/openstackclient/image/v1/image.py
@@ -355,6 +355,13 @@ class ListImage(lister.Lister):
             metavar="<size>",
             help=argparse.SUPPRESS,
         )
+        parser.add_argument(
+            '--sort',
+            metavar="<key>[:<direction>]",
+            help="Sort output by selected keys and directions(asc or desc) "
+                 "(default: asc), multiple keys and directions can be "
+                 "specified separated by comma",
+        )
         return parser
 
     def take_action(self, parsed_args):
@@ -409,6 +416,9 @@ class ListImage(lister.Lister):
                 value=value,
                 property_field='properties',
             )
+
+        data = utils.sort_items(data, parsed_args.sort)
+
         return (
             column_headers,
             (utils.get_dict_properties(
diff --git a/openstackclient/image/v2/image.py b/openstackclient/image/v2/image.py
index 4eda506c02..afc99e8578 100644
--- a/openstackclient/image/v2/image.py
+++ b/openstackclient/image/v2/image.py
@@ -105,6 +105,13 @@ class ListImage(lister.Lister):
             metavar="<size>",
             help=argparse.SUPPRESS,
         )
+        parser.add_argument(
+            '--sort',
+            metavar="<key>[:<direction>]",
+            help="Sort output by selected keys and directions(asc or desc) "
+                 "(default: asc), multiple keys and directions can be "
+                 "specified separated by comma",
+        )
         return parser
 
     def take_action(self, parsed_args):
@@ -160,6 +167,9 @@ class ListImage(lister.Lister):
                 value=value,
                 property_field='properties',
             )
+
+        data = utils.sort_items(data, parsed_args.sort)
+
         return (
             column_headers,
             (utils.get_dict_properties(
diff --git a/openstackclient/tests/common/test_utils.py b/openstackclient/tests/common/test_utils.py
index 583ab99c5c..cda0b1351d 100644
--- a/openstackclient/tests/common/test_utils.py
+++ b/openstackclient/tests/common/test_utils.py
@@ -58,6 +58,68 @@ class TestUtils(test_utils.TestCase):
                               utils.get_password,
                               mock_stdin)
 
+    def get_test_items(self):
+        item1 = {'a': 1, 'b': 2}
+        item2 = {'a': 1, 'b': 3}
+        item3 = {'a': 2, 'b': 2}
+        item4 = {'a': 2, 'b': 1}
+        return [item1, item2, item3, item4]
+
+    def test_sort_items_with_one_key(self):
+        items = self.get_test_items()
+        sort_str = 'b'
+        expect_items = [items[3], items[0], items[2], items[1]]
+        self.assertEqual(expect_items, utils.sort_items(items, sort_str))
+
+    def test_sort_items_with_multiple_keys(self):
+        items = self.get_test_items()
+        sort_str = 'a,b'
+        expect_items = [items[0], items[1], items[3], items[2]]
+        self.assertEqual(expect_items, utils.sort_items(items, sort_str))
+
+    def test_sort_items_all_with_direction(self):
+        items = self.get_test_items()
+        sort_str = 'a:desc,b:desc'
+        expect_items = [items[2], items[3], items[1], items[0]]
+        self.assertEqual(expect_items, utils.sort_items(items, sort_str))
+
+    def test_sort_items_some_with_direction(self):
+        items = self.get_test_items()
+        sort_str = 'a,b:desc'
+        expect_items = [items[1], items[0], items[2], items[3]]
+        self.assertEqual(expect_items, utils.sort_items(items, sort_str))
+
+    def test_sort_items_with_object(self):
+        item1 = mock.Mock(a=1, b=2)
+        item2 = mock.Mock(a=1, b=3)
+        item3 = mock.Mock(a=2, b=2)
+        item4 = mock.Mock(a=2, b=1)
+        items = [item1, item2, item3, item4]
+        sort_str = 'b,a'
+        expect_items = [item4, item1, item3, item2]
+        self.assertEqual(expect_items, utils.sort_items(items, sort_str))
+
+    def test_sort_items_with_empty_key(self):
+        items = self.get_test_items()
+        sort_srt = ''
+        self.assertEqual(items, utils.sort_items(items, sort_srt))
+        sort_srt = None
+        self.assertEqual(items, utils.sort_items(items, sort_srt))
+
+    def test_sort_items_with_invalid_key(self):
+        items = self.get_test_items()
+        sort_str = 'c'
+        self.assertRaises(exceptions.CommandError,
+                          utils.sort_items,
+                          items, sort_str)
+
+    def test_sort_items_with_invalid_direction(self):
+        items = self.get_test_items()
+        sort_str = 'a:bad_dir'
+        self.assertRaises(exceptions.CommandError,
+                          utils.sort_items,
+                          items, sort_str)
+
 
 class NoUniqueMatch(Exception):
     pass
diff --git a/openstackclient/tests/image/v1/test_image.py b/openstackclient/tests/image/v1/test_image.py
index 355f8c823c..2776e7448d 100644
--- a/openstackclient/tests/image/v1/test_image.py
+++ b/openstackclient/tests/image/v1/test_image.py
@@ -470,6 +470,35 @@ class TestImageList(TestImage):
         ), )
         self.assertEqual(datalist, tuple(data))
 
+    @mock.patch('openstackclient.common.utils.sort_items')
+    def test_image_list_sort_option(self, si_mock):
+        si_mock.return_value = [
+            copy.deepcopy(image_fakes.IMAGE)
+        ]
+
+        arglist = ['--sort', 'name:asc']
+        verifylist = [('sort', 'name:asc')]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        # DisplayCommandBase.take_action() returns two tuples
+        columns, data = self.cmd.take_action(parsed_args)
+        self.api_mock.image_list.assert_called_with(
+            detailed=False
+        )
+        si_mock.assert_called_with(
+            [image_fakes.IMAGE],
+            'name:asc'
+        )
+
+        collist = ('ID', 'Name')
+
+        self.assertEqual(collist, columns)
+        datalist = ((
+            image_fakes.image_id,
+            image_fakes.image_name
+        ), )
+        self.assertEqual(datalist, tuple(data))
+
 
 class TestImageSet(TestImage):
 
diff --git a/openstackclient/tests/image/v2/test_image.py b/openstackclient/tests/image/v2/test_image.py
index db3c32df88..6a28b1ec2d 100644
--- a/openstackclient/tests/image/v2/test_image.py
+++ b/openstackclient/tests/image/v2/test_image.py
@@ -255,3 +255,30 @@ class TestImageList(TestImage):
             image_fakes.image_name,
         ), )
         self.assertEqual(datalist, tuple(data))
+
+    @mock.patch('openstackclient.common.utils.sort_items')
+    def test_image_list_sort_option(self, si_mock):
+        si_mock.return_value = [
+            copy.deepcopy(image_fakes.IMAGE)
+        ]
+
+        arglist = ['--sort', 'name:asc']
+        verifylist = [('sort', 'name:asc')]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        # DisplayCommandBase.take_action() returns two tuples
+        columns, data = self.cmd.take_action(parsed_args)
+        self.api_mock.image_list.assert_called_with()
+        si_mock.assert_called_with(
+            [image_fakes.IMAGE],
+            'name:asc'
+        )
+
+        collist = ('ID', 'Name')
+
+        self.assertEqual(collist, columns)
+        datalist = ((
+            image_fakes.image_id,
+            image_fakes.image_name
+        ), )
+        self.assertEqual(datalist, tuple(data))