diff --git a/REDIS_COMMANDS.md b/REDIS_COMMANDS.md
index db7a154..df16b3e 100644
--- a/REDIS_COMMANDS.md
+++ b/REDIS_COMMANDS.md
@@ -14,6 +14,8 @@ list of [unimplemented commands](#unimplemented-commands).
    Get the value of a key
  * [GETDEL](https://redis.io/commands/getdel/)
    Get the value of a key and delete the key
+ * [GETEX](https://redis.io/commands/getex/)
+   Get the value of a key and optionally set its expiration
  * [GETRANGE](https://redis.io/commands/getrange/)
    Get a substring of the string stored at a key
  * [GETSET](https://redis.io/commands/getset/)
@@ -730,16 +732,14 @@ All the redis commands are implemented in fakeredis with these exceptions:
  * [GEOSEARCHSTORE](https://redis.io/commands/geosearchstore/)
    Query a sorted set representing a geospatial index to fetch members inside an area of a box or a circle, and store the result in another key.
 
-### string
- * [GETEX](https://redis.io/commands/getex/)
-   Get the value of a key and optionally set its expiration
- * [LCS](https://redis.io/commands/lcs/)
-   Find longest common substring
-
 ### hash
  * [HRANDFIELD](https://redis.io/commands/hrandfield/)
    Get one or multiple random fields from a hash
 
+### string
+ * [LCS](https://redis.io/commands/lcs/)
+   Find longest common substring
+
 ### hyperloglog
  * [PFDEBUG](https://redis.io/commands/pfdebug/)
    Internal commands for debugging HyperLogLog values
diff --git a/fakeredis/commands_mixins/string_mixin.py b/fakeredis/commands_mixins/string_mixin.py
index ac35280..7b39605 100644
--- a/fakeredis/commands_mixins/string_mixin.py
+++ b/fakeredis/commands_mixins/string_mixin.py
@@ -193,3 +193,36 @@ class StringCommandsMixin:
     @command((Key(bytes), Int, Int))
     def substr(self, key, start, end):
         return self.getrange(key, start, end)
+
+    @command((Key(bytes),), (bytes,))
+    def getex(self, key, *args):
+        i, count_options, expire_time, diff = 0, 0, None, None
+        while i < len(args):
+            count_options += 1
+            if casematch(args[i], b'ex') and i + 1 < len(args):
+                diff = Int.decode(args[i + 1])
+                expire_time = self._db.time + diff
+                i += 2
+            elif casematch(args[i], b'px') and i + 1 < len(args):
+                diff = Int.decode(args[i + 1])
+                expire_time = (self._db.time * 1000 + diff) / 1000.0
+                i += 2
+            elif casematch(args[i], b'exat') and i + 1 < len(args):
+                expire_time = Int.decode(args[i + 1])
+                i += 2
+            elif casematch(args[i], b'pxat') and i + 1 < len(args):
+                expire_time = Int.decode(args[i + 1]) / 1000.0
+                i += 2
+            elif casematch(args[i], b'persist'):
+                expire_time = None
+                i += 1
+            else:
+                raise SimpleError(msgs.SYNTAX_ERROR_MSG)
+        if ((expire_time is not None and (expire_time <= 0 or expire_time * 1000 >= 2 ** 63))
+                or (diff is not None and (diff <= 0 or diff * 1000 >= 2 ** 63))):
+            raise SimpleError(msgs.INVALID_EXPIRE_MSG.format('getex'))
+        if count_options > 1:
+            raise SimpleError(msgs.SYNTAX_ERROR_MSG)
+
+        key.expireat = expire_time
+        return key.get(None)
diff --git a/scripts/create_issues.py b/scripts/create_issues.py
index 45d21c6..b2c43e4 100644
--- a/scripts/create_issues.py
+++ b/scripts/create_issues.py
@@ -64,11 +64,12 @@ class GithubData:
         link = f"https://redis.io/commands/{cmd.replace(' ', '-')}/"
         title = f"Implement support for `{cmd.upper()}` ({group} command)"
         filename = f'{group}_mixin.py'
-        body = f"""Implement support for command `{cmd.upper()}` in {filename}.
+        body = f"""
+Implement support for command `{cmd.upper()}` in {filename}.
         
-        {summary}. 
+{summary}. 
         
-        Here is the [Official documentation]({link})"""
+Here is the [Official documentation]({link})"""
         labels = [f'{group}-commands', 'enhancement', 'help wanted']
         for label in labels:
             if label not in self.labels:

diff --git a/test/test_mixins/test_server_commands.py b/test/test_mixins/test_server_commands.py
index c92bc8d..9859a22 100644
--- a/test/test_mixins/test_server_commands.py
+++ b/test/test_mixins/test_server_commands.py
@@ -4,8 +4,6 @@ from time import sleep
 import pytest
 from redis.exceptions import ResponseError
 
-from .. import testtools
-
 
 def test_swapdb(r, create_redis):
     r1 = create_redis(1)
diff --git a/test/test_mixins/test_string_commands.py b/test/test_mixins/test_string_commands.py
index 8bc351a..03754e3 100644
--- a/test/test_mixins/test_string_commands.py
+++ b/test/test_mixins/test_string_commands.py
@@ -1,5 +1,6 @@
 from __future__ import annotations
 
+import time
 from datetime import timedelta
 
 import pytest
@@ -476,3 +477,38 @@ def test_setitem_getitem(r):
 def test_getitem_non_existent_key(r):
     assert r.keys() == []
     assert 'noexists' not in r.keys()
+
+
+@pytest.mark.slow
+def test_getex(r: redis.Redis):
+    # Exceptions
+    with pytest.raises(redis.ResponseError):
+        raw_command(r, 'getex', 'foo', 'px', 1000, 'ex', 1)
+    with pytest.raises(redis.ResponseError):
+        raw_command(r, 'getex', 'foo', 'dsac', 1000, 'ex', 1)
+
+    r.set('foo', 'val')
+    assert r.getex('foo', ex=1) == b'val'
+    time.sleep(1.5)
+    assert r.get('foo') is None
+
+    r.set('foo2', 'val')
+    assert r.getex('foo2', px=1000) == b'val'
+    time.sleep(1.5)
+    assert r.get('foo2') is None
+
+    r.set('foo4', 'val')
+    r.getex('foo4', exat=int(time.time() + 1))
+    time.sleep(1.5)
+    assert r.get('foo4') is None
+
+    r.set('foo2', 'val')
+    r.getex('foo2', pxat=int(time.time() + 1) * 1000)
+    time.sleep(1.5)
+    assert r.get('foo2') is None
+
+    r.setex('foo5', 1, 'val')
+    r.getex('foo5', persist=True)
+    assert r.ttl('foo5') == -1
+    time.sleep(1.5)
+    assert r.get('foo5') == b'val'

Implement support for `GETEX` (string command)
Implement support for command `GETEX` in string_mixin.py.
        
        Get the value of a key and optionally set its expiration. 
        
        Here is the [Official documentation](https://redis.io/commands/getex/)
test/test_mixins/test_string_commands.py::test_getex[FakeStrictRedis]
test/test_mixins/test_server_commands.py::test_swapdb[FakeStrictRedis] test/test_mixins/test_server_commands.py::test_swapdb_same_db[FakeStrictRedis] test/test_mixins/test_server_commands.py::test_save[FakeStrictRedis] test/test_mixins/test_server_commands.py::test_bgsave[FakeStrictRedis] test/test_mixins/test_server_commands.py::test_lastsave[FakeStrictRedis] test/test_mixins/test_server_commands.py::test_bgsave_timestamp_update[FakeStrictRedis] test/test_mixins/test_server_commands.py::test_save_timestamp_update[FakeStrictRedis] test/test_mixins/test_server_commands.py::test_dbsize[FakeStrictRedis] test/test_mixins/test_server_commands.py::test_flushdb[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_append[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_append_with_no_preexisting_key[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_append_wrong_type[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_decr[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_decr_newkey[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_decr_expiry[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_decr_badtype[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_get_does_not_exist[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_get_with_non_str_keys[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_get_invalid_type[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_getset_exists[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_getset_wrong_type[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_getdel[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_getdel_doesnt_exist[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_incr_with_no_preexisting_key[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_incr_by[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_incr_preexisting_key[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_incr_expiry[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_incr_bad_type[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_incr_with_float[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_incr_followed_by_mget[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_incr_followed_by_mget_returns_strings[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_incrbyfloat[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_incrbyfloat_with_noexist[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_incrbyfloat_expiry[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_incrbyfloat_bad_type[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_incrbyfloat_precision[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_mget[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_mget_with_no_keys[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_mget_mixed_types[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_mset_with_no_keys[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_mset[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_msetnx[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_setex[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_setex_using_timedelta[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_setex_using_float[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_setex_overflow[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_set_ex[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_set_ex_using_timedelta[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_set_ex_overflow[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_set_px_overflow[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_set_px[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_set_px_using_timedelta[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_set_conflicting_expire_options[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_set_raises_wrong_ex[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_set_using_timedelta_raises_wrong_ex[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_set_raises_wrong_px[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_set_using_timedelta_raises_wrong_px[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_setex_raises_wrong_ex[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_setex_using_timedelta_raises_wrong_ex[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_setnx[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_set_nx[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_set_xx[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_set_get[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_set_get_xx[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_set_get_nx_redis6[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_set_get_nx_redis7[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_substr[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_substr_noexist_key[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_substr_wrong_type[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_strlen[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_strlen_wrong_type[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_setrange[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_setrange_expiry[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_large_command[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_saving_non_ascii_chars_as_value[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_saving_unicode_type_as_value[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_saving_non_ascii_chars_as_key[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_saving_unicode_type_as_key[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_future_newbytes[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_future_newstr[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_setitem_getitem[FakeStrictRedis] test/test_mixins/test_string_commands.py::test_getitem_non_existent_key[FakeStrictRedis]