diff --git a/swh/model/cli.py b/swh/model/cli.py
index 036844dfc754601f9b3e60b1f68942815af1a33f..82af76f8cd5827167133edc1bb0556145d5d688e 100644
--- a/swh/model/cli.py
+++ b/swh/model/cli.py
@@ -35,7 +35,7 @@ def pid_of_dir(path):
     return pids.persistent_identifier(pids.DIRECTORY, object)
 
 
-def identify_object(obj_type, obj):
+def identify_object(obj_type, follow_symlinks, obj):
     if obj_type == 'auto':
         if os.path.isfile(obj):
             obj_type = 'content'
@@ -44,29 +44,40 @@ def identify_object(obj_type, obj):
         else:  # shouldn't happen, due to path validation
             raise click.BadParameter('%s is neither a file nor a directory' %
                                      obj)
+
+    path = obj
+    if follow_symlinks and os.path.islink(obj):
+        path = os.path.realpath(obj)
+
     pid = None
     if obj_type == 'content':
-        pid = pid_of_file(obj)
+        pid = pid_of_file(path)
     elif obj_type == 'directory':
-        pid = pid_of_dir(obj)
+        pid = pid_of_dir(path)
     else:  # shouldn't happen, due to option validation
         raise click.BadParameter('invalid object type: ' + obj_type)
 
+    # note: we return original obj instead of path here, to preserve user-given
+    # file name in output
     return (obj, pid)
 
 
 @click.command()
+@click.option('--dereference/--no-dereference', 'follow_symlinks',
+              default=True,
+              help='follow (or not) symlinks for OBJECTS passed as arguments '
+              + '(default: follow)')
+@click.option('--filename/--no-filename', 'show_filename', default=True,
+              help='show/hide file name (default: show)')
 @click.option('--type', '-t', 'obj_type', default='auto',
               type=click.Choice(['auto', 'content', 'directory']),
               help='type of object to identify (default: auto)')
 @click.option('--verify', '-v', metavar='PID', type=PidParamType(),
               help='reference identifier to be compared with computed one')
-@click.option('--filename/--no-filename', 'show_filename', default=True,
-              help='show/hide file name (default: show)')
 @click.argument('objects', nargs=-1,
                 type=click.Path(exists=True, readable=True,
                                 allow_dash=True, path_type=bytes))
-def identify(obj_type, verify, show_filename, objects):
+def identify(obj_type, verify, show_filename, follow_symlinks, objects):
     """Compute the Software Heritage persistent identifier (PID) for the given
     source code object(s).
 
@@ -92,7 +103,7 @@ def identify(obj_type, verify, show_filename, objects):
     if verify and len(objects) != 1:
         raise click.BadParameter('verification requires a single object')
 
-    results = map(partial(identify_object, obj_type), objects)
+    results = map(partial(identify_object, obj_type, follow_symlinks), objects)
 
     if verify:
         pid = next(results)[1]
diff --git a/swh/model/tests/test_cli.py b/swh/model/tests/test_cli.py
index d8e68b9e21fba992d9fbfa77c89ea2aebea9469e..45dd36f39730a53240ce6678982765a57fadd2fd 100644
--- a/swh/model/tests/test_cli.py
+++ b/swh/model/tests/test_cli.py
@@ -22,6 +22,10 @@ class TestIdentify(DataMixin, unittest.TestCase):
         super().setUp()
         self.runner = CliRunner()
 
+    def assertPidOK(self, result, pid):
+        self.assertEqual(result.exit_code, 0)
+        self.assertEqual(result.output.split()[0], pid)
+
     def test_content_id(self):
         """identify file content"""
         self.make_contents(self.tmpdir_name)
@@ -45,6 +49,21 @@ class TestIdentify(DataMixin, unittest.TestCase):
         self.assertEqual(result.output.split()[0],
                          'swh:1:dir:e8b0f1466af8608c8a3fb9879db172b887e80759')
 
+    def test_symlink(self):
+        """identify symlink --- both itself and target"""
+        regular = os.path.join(self.tmpdir_name, b'foo.txt')
+        link = os.path.join(self.tmpdir_name, b'bar.txt')
+        open(regular, 'w').write('foo\n')
+        os.symlink(os.path.basename(regular), link)
+
+        result = self.runner.invoke(cli.identify, [link])
+        self.assertPidOK(result,
+                         'swh:1:cnt:257cc5642cb1a054f08cc83f2d943e56fd3ebe99')
+
+        result = self.runner.invoke(cli.identify, ['--no-dereference', link])
+        self.assertPidOK(result,
+                         'swh:1:cnt:996f1789ff67c0e3f69ef5933a55d54c5d0e9954')
+
     def test_show_filename(self):
         """filename is shown by default"""
         self.make_contents(self.tmpdir_name)