diff --git a/doc/source/command-objects/image.rst b/doc/source/command-objects/image.rst
index 8dce3662f3..c3fe77a10b 100644
--- a/doc/source/command-objects/image.rst
+++ b/doc/source/command-objects/image.rst
@@ -238,6 +238,7 @@ Set image properties
         [--checksum <checksum>]
         [--stdin]
         [--property <key=value> [...] ]
+        [--tag <tag> [...] ]
         [--architecture <architecture>]
         [--instance-id <instance-id>]
         [--kernel-id <kernel-id>]
@@ -344,6 +345,14 @@ Set image properties
 
     Set a property on this image (repeat option to set multiple properties)
 
+    .. versionadded:: 2
+
+.. option:: --tag <tag>
+
+    Set a tag on this image (repeat for multiple values)
+
+    .. versionadded:: 2
+
 .. option:: --architecture <architecture>
 
     Operating system architecture
diff --git a/openstackclient/image/v2/image.py b/openstackclient/image/v2/image.py
index 11c7483bdb..7ef1f7806a 100644
--- a/openstackclient/image/v2/image.py
+++ b/openstackclient/image/v2/image.py
@@ -57,8 +57,7 @@ def _format_image(image):
             properties[key] = image.get(key)
 
     # format the tags if they are there
-    if image.get('tags'):
-        info['tags'] = utils.format_list(image.get('tags'))
+    info['tags'] = utils.format_list(image.get('tags'))
 
     # add properties back into the dictionary as a top-level key
     if properties:
@@ -540,7 +539,6 @@ class SetImage(show.ShowOne):
         # --force - needs adding
         # --checksum - maybe could be done client side
         # --stdin - could be implemented
-        # --tags - needs adding
         parser.add_argument(
             "image",
             metavar="<image>",
@@ -610,6 +608,15 @@ class SetImage(show.ShowOne):
             help="Set a property on this image "
                  "(repeat option to set multiple properties)",
         )
+        parser.add_argument(
+            "--tag",
+            dest="tags",
+            metavar="<tag>",
+            default=[],
+            action='append',
+            help="Set a tag on this image "
+                 "(repeat option to set multiple tags)",
+        )
         parser.add_argument(
             "--architecture",
             metavar="<architecture>",
@@ -669,7 +676,7 @@ class SetImage(show.ShowOne):
         copy_attrs = ('architecture', 'container_format', 'disk_format',
                       'file', 'instance_id', 'kernel_id', 'locations',
                       'min_disk', 'min_ram', 'name', 'os_distro', 'os_version',
-                      'owner', 'prefix', 'progress', 'ramdisk_id')
+                      'owner', 'prefix', 'progress', 'ramdisk_id', 'tags')
         for attr in copy_attrs:
             if attr in parsed_args:
                 val = getattr(parsed_args, attr, None)
@@ -705,6 +712,10 @@ class SetImage(show.ShowOne):
         image = utils.find_resource(
             image_client.images, parsed_args.image)
 
+        if parsed_args.tags:
+            # Tags should be extended, but duplicates removed
+            kwargs['tags'] = list(set(image.tags).union(set(parsed_args.tags)))
+
         image = image_client.images.update(image.id, **kwargs)
         info = {}
         info.update(image)
diff --git a/openstackclient/tests/compute/v2/test_server.py b/openstackclient/tests/compute/v2/test_server.py
index 4df18f0523..1e99bcd0ba 100644
--- a/openstackclient/tests/compute/v2/test_server.py
+++ b/openstackclient/tests/compute/v2/test_server.py
@@ -410,13 +410,14 @@ class TestServerImageCreate(TestServer):
             compute_fakes.server_name,
         )
 
-        collist = ('id', 'name', 'owner', 'protected', 'visibility')
+        collist = ('id', 'name', 'owner', 'protected', 'tags', 'visibility')
         self.assertEqual(collist, columns)
         datalist = (
             image_fakes.image_id,
             image_fakes.image_name,
             image_fakes.image_owner,
             image_fakes.image_protected,
+            image_fakes.image_tags,
             image_fakes.image_visibility,
         )
         self.assertEqual(datalist, data)
@@ -441,13 +442,14 @@ class TestServerImageCreate(TestServer):
             'img-nam',
         )
 
-        collist = ('id', 'name', 'owner', 'protected', 'visibility')
+        collist = ('id', 'name', 'owner', 'protected', 'tags', 'visibility')
         self.assertEqual(collist, columns)
         datalist = (
             image_fakes.image_id,
             image_fakes.image_name,
             image_fakes.image_owner,
             image_fakes.image_protected,
+            image_fakes.image_tags,
             image_fakes.image_visibility,
         )
         self.assertEqual(datalist, data)
diff --git a/openstackclient/tests/image/v2/fakes.py b/openstackclient/tests/image/v2/fakes.py
index 1a9e301a01..11ad455df2 100644
--- a/openstackclient/tests/image/v2/fakes.py
+++ b/openstackclient/tests/image/v2/fakes.py
@@ -13,6 +13,7 @@
 #   under the License.
 #
 
+import copy
 import mock
 
 from openstackclient.tests import fakes
@@ -25,6 +26,7 @@ image_name = 'graven'
 image_owner = 'baal'
 image_protected = False
 image_visibility = 'public'
+image_tags = []
 
 IMAGE = {
     'id': image_id,
@@ -32,11 +34,16 @@ IMAGE = {
     'owner': image_owner,
     'protected': image_protected,
     'visibility': image_visibility,
+    'tags': image_tags
 }
 
 IMAGE_columns = tuple(sorted(IMAGE))
 IMAGE_data = tuple((IMAGE[x] for x in sorted(IMAGE)))
 
+IMAGE_SHOW = copy.copy(IMAGE)
+IMAGE_SHOW['tags'] = ''
+IMAGE_SHOW_data = tuple((IMAGE_SHOW[x] for x in sorted(IMAGE_SHOW)))
+
 member_status = 'pending'
 MEMBER = {
     'member_id': identity_fakes.project_id,
@@ -117,6 +124,14 @@ IMAGE_schema = {
             "type": "string",
             "description": "Status of the image (READ-ONLY)"
         },
+        "tags": {
+            "items": {
+                "type": "string",
+                "maxLength": 255
+            },
+            "type": "array",
+            "description": "List of strings related to the image"
+        },
         "visibility": {
             "enum": [
                 "public",
diff --git a/openstackclient/tests/image/v2/test_image.py b/openstackclient/tests/image/v2/test_image.py
index ce2974d692..46da9c6893 100644
--- a/openstackclient/tests/image/v2/test_image.py
+++ b/openstackclient/tests/image/v2/test_image.py
@@ -96,7 +96,7 @@ class TestImageCreate(TestImage):
         )
 
         self.assertEqual(image_fakes.IMAGE_columns, columns)
-        self.assertEqual(image_fakes.IMAGE_data, data)
+        self.assertEqual(image_fakes.IMAGE_SHOW_data, data)
 
     @mock.patch('glanceclient.common.utils.get_data_file', name='Open')
     def test_image_reserve_options(self, mock_open):
@@ -151,7 +151,7 @@ class TestImageCreate(TestImage):
         )
 
         self.assertEqual(image_fakes.IMAGE_columns, columns)
-        self.assertEqual(image_fakes.IMAGE_data, data)
+        self.assertEqual(image_fakes.IMAGE_SHOW_data, data)
 
     @mock.patch('glanceclient.common.utils.get_data_file', name='Open')
     def test_image_create_file(self, mock_open):
@@ -208,7 +208,7 @@ class TestImageCreate(TestImage):
         )
 
         self.assertEqual(image_fakes.IMAGE_columns, columns)
-        self.assertEqual(image_fakes.IMAGE_data, data)
+        self.assertEqual(image_fakes.IMAGE_SHOW_data, data)
 
     def test_image_create_dead_options(self):
 
@@ -812,6 +812,81 @@ class TestImageSet(TestImage):
             **kwargs
         )
 
+    def test_image_set_tag(self):
+        arglist = [
+            '--tag', 'test-tag',
+            image_fakes.image_name,
+        ]
+        verifylist = [
+            ('tags', ['test-tag']),
+            ('image', image_fakes.image_name),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        # DisplayCommandBase.take_action() returns two tuples
+        self.cmd.take_action(parsed_args)
+
+        kwargs = {
+            'tags': ['test-tag'],
+        }
+        # ImageManager.update(image, **kwargs)
+        self.images_mock.update.assert_called_with(
+            image_fakes.image_id,
+            **kwargs
+        )
+
+    def test_image_set_tag_merge(self):
+        old_image = copy.copy(image_fakes.IMAGE)
+        old_image['tags'] = ['old1', 'new2']
+        self.images_mock.get.return_value = self.model(**old_image)
+        arglist = [
+            '--tag', 'test-tag',
+            image_fakes.image_name,
+        ]
+        verifylist = [
+            ('tags', ['test-tag']),
+            ('image', image_fakes.image_name),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        # DisplayCommandBase.take_action() returns two tuples
+        self.cmd.take_action(parsed_args)
+
+        kwargs = {
+            'tags': ['old1', 'new2', 'test-tag'],
+        }
+        # ImageManager.update(image, **kwargs)
+        a, k = self.images_mock.update.call_args
+        self.assertEqual(image_fakes.image_id, a[0])
+        self.assertTrue('tags' in k)
+        self.assertEqual(set(kwargs['tags']), set(k['tags']))
+
+    def test_image_set_tag_merge_dupe(self):
+        old_image = copy.copy(image_fakes.IMAGE)
+        old_image['tags'] = ['old1', 'new2']
+        self.images_mock.get.return_value = self.model(**old_image)
+        arglist = [
+            '--tag', 'old1',
+            image_fakes.image_name,
+        ]
+        verifylist = [
+            ('tags', ['old1']),
+            ('image', image_fakes.image_name),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        # DisplayCommandBase.take_action() returns two tuples
+        self.cmd.take_action(parsed_args)
+
+        kwargs = {
+            'tags': ['new2', 'old1'],
+        }
+        # ImageManager.update(image, **kwargs)
+        a, k = self.images_mock.update.call_args
+        self.assertEqual(image_fakes.image_id, a[0])
+        self.assertTrue('tags' in k)
+        self.assertEqual(set(kwargs['tags']), set(k['tags']))
+
     def test_image_set_dead_options(self):
 
         arglist = [
@@ -861,4 +936,4 @@ class TestImageShow(TestImage):
         )
 
         self.assertEqual(image_fakes.IMAGE_columns, columns)
-        self.assertEqual(image_fakes.IMAGE_data, data)
+        self.assertEqual(image_fakes.IMAGE_SHOW_data, data)