diff --git a/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java b/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java
index f2c6c625ce..8b09c6b2e2 100644
--- a/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java
+++ b/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java
@@ -19,15 +19,6 @@
  */
 package io.lettuce.core;
 
-import static io.lettuce.core.protocol.CommandType.*;
-
-import java.time.Duration;
-import java.time.Instant;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
 import io.lettuce.core.GeoArgs.Unit;
 import io.lettuce.core.api.StatefulConnection;
 import io.lettuce.core.api.async.*;
@@ -50,6 +41,19 @@
 import io.lettuce.core.protocol.ProtocolKeyword;
 import io.lettuce.core.protocol.RedisCommand;
 
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static io.lettuce.core.protocol.CommandType.EXEC;
+import static io.lettuce.core.protocol.CommandType.GEORADIUS;
+import static io.lettuce.core.protocol.CommandType.GEORADIUSBYMEMBER;
+import static io.lettuce.core.protocol.CommandType.GEORADIUSBYMEMBER_RO;
+import static io.lettuce.core.protocol.CommandType.GEORADIUS_RO;
+
 /**
  * An asynchronous and thread-safe API for a Redis connection.
  *
@@ -794,6 +798,27 @@ public RedisFuture<Boolean> expire(K key, Duration seconds, ExpireArgs expireArg
         return expire(key, seconds.toMillis() / 1000, expireArgs);
     }
 
+    @Override
+    public RedisFuture<Boolean> hexpire(K key, long seconds, K... fields) {
+        return hexpire(key, seconds, null, fields);
+    }
+
+    @Override
+    public RedisFuture<Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, K... fields) {
+        return dispatch(commandBuilder.hexpire(key, seconds, expireArgs, fields));
+    }
+
+    @Override
+    public RedisFuture<Boolean> hexpire(K key, Duration seconds, K... fields) {
+        return hexpire(key, seconds, null, fields);
+    }
+
+    @Override
+    public RedisFuture<Boolean> hexpire(K key, Duration seconds, ExpireArgs expireArgs, K... fields) {
+        LettuceAssert.notNull(seconds, "Timeout must not be null");
+        return hexpire(key, seconds.toMillis() / 1000, expireArgs, fields);
+    }
+
     @Override
     public RedisFuture<Boolean> expireat(K key, long timestamp) {
         return expireat(key, timestamp, null);
@@ -826,11 +851,49 @@ public RedisFuture<Boolean> expireat(K key, Instant timestamp, ExpireArgs expire
         return expireat(key, timestamp.toEpochMilli() / 1000, expireArgs);
     }
 
+    @Override
+    public RedisFuture<Boolean> hexpireat(K key, long timestamp, K... fields) {
+        return hexpireat(key, timestamp, null, fields);
+    }
+
+    @Override
+    public RedisFuture<Boolean> hexpireat(K key, long timestamp, ExpireArgs expireArgs, K... fields) {
+        return dispatch(commandBuilder.hexpireat(key, timestamp, expireArgs, fields));
+
+    }
+
+    @Override
+    public RedisFuture<Boolean> hexpireat(K key, Date timestamp, K... fields) {
+        return hexpireat(key, timestamp, null, fields);
+    }
+
+    @Override
+    public RedisFuture<Boolean> hexpireat(K key, Date timestamp, ExpireArgs expireArgs, K... fields) {
+        LettuceAssert.notNull(timestamp, "Timestamp must not be null");
+        return hexpireat(key, timestamp.getTime() / 1000, expireArgs, fields);
+    }
+
+    @Override
+    public RedisFuture<Boolean> hexpireat(K key, Instant timestamp, K... fields) {
+        return hexpireat(key, timestamp, null, fields);
+    }
+
+    @Override
+    public RedisFuture<Boolean> hexpireat(K key, Instant timestamp, ExpireArgs expireArgs, K... fields) {
+        LettuceAssert.notNull(timestamp, "Timestamp must not be null");
+        return hexpireat(key, timestamp.toEpochMilli() / 1000, expireArgs, fields);
+    }
+
     @Override
     public RedisFuture<Long> expiretime(K key) {
         return dispatch(commandBuilder.expiretime(key));
     }
 
+    @Override
+    public RedisFuture<Long> hexpiretime(K key, K... fields) {
+        return dispatch(commandBuilder.hexpiretime(key, fields));
+    }
+
     @Override
     public <T> RedisFuture<T> fcall(String function, ScriptOutputType type, K... keys) {
         return dispatch(commandBuilder.fcall(function, type, false, keys));
@@ -1489,6 +1552,11 @@ public RedisFuture<Boolean> persist(K key) {
         return dispatch(commandBuilder.persist(key));
     }
 
+    @Override
+    public RedisFuture<Boolean> hpersist(K key, K... fields) {
+        return dispatch(commandBuilder.hpersist(key, fields));
+    }
+
     @Override
     public RedisFuture<Boolean> pexpire(K key, long milliseconds) {
         return pexpire(key, milliseconds, null);
diff --git a/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java b/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java
index 47b473495e..47006ac03d 100644
--- a/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java
+++ b/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java
@@ -19,16 +19,6 @@
  */
 package io.lettuce.core;
 
-import static io.lettuce.core.protocol.CommandType.*;
-
-import java.time.Duration;
-import java.time.Instant;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.Supplier;
-
 import io.lettuce.core.GeoArgs.Unit;
 import io.lettuce.core.api.StatefulConnection;
 import io.lettuce.core.api.reactive.*;
@@ -59,6 +49,20 @@
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Supplier;
+
+import static io.lettuce.core.protocol.CommandType.EXEC;
+import static io.lettuce.core.protocol.CommandType.GEORADIUS;
+import static io.lettuce.core.protocol.CommandType.GEORADIUSBYMEMBER;
+import static io.lettuce.core.protocol.CommandType.GEORADIUSBYMEMBER_RO;
+import static io.lettuce.core.protocol.CommandType.GEORADIUS_RO;
+
 /**
  * A reactive and thread-safe API for a Redis connection.
  *
@@ -854,6 +858,27 @@ public Mono<Boolean> expire(K key, Duration seconds, ExpireArgs expireArgs) {
         return expire(key, seconds.toMillis() / 1000, expireArgs);
     }
 
+    @Override
+    public Mono<Boolean> hexpire(K key, long seconds, K... fields) {
+        return hexpire(key, seconds, null, fields);
+    }
+
+    @Override
+    public Mono<Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, K... fields) {
+        return createMono(() -> commandBuilder.hexpire(key, seconds, expireArgs, fields));
+    }
+
+    @Override
+    public Mono<Boolean> hexpire(K key, Duration seconds, K... fields) {
+        return hexpire(key, seconds, null, fields);
+    }
+
+    @Override
+    public Mono<Boolean> hexpire(K key, Duration seconds, ExpireArgs expireArgs, K... fields) {
+        LettuceAssert.notNull(seconds, "Timeout must not be null");
+        return hexpire(key, seconds.toMillis() / 1000, expireArgs, fields);
+    }
+
     @Override
     public Mono<Boolean> expireat(K key, long timestamp) {
         return expireat(key, timestamp, null);
@@ -886,11 +911,48 @@ public Mono<Boolean> expireat(K key, Instant timestamp, ExpireArgs expireArgs) {
         return expireat(key, timestamp.toEpochMilli() / 1000, expireArgs);
     }
 
+    @Override
+    public Mono<Boolean> hexpireat(K key, long timestamp, K... fields) {
+        return hexpireat(key, timestamp, null, fields);
+    }
+
+    @Override
+    public Mono<Boolean> hexpireat(K key, long timestamp, ExpireArgs expireArgs, K... fields) {
+        return createMono(() -> commandBuilder.hexpireat(key, timestamp, expireArgs, fields));
+    }
+
+    @Override
+    public Mono<Boolean> hexpireat(K key, Date timestamp, K... fields) {
+        return hexpireat(key, timestamp, null, fields);
+    }
+
+    @Override
+    public Mono<Boolean> hexpireat(K key, Date timestamp, ExpireArgs expireArgs, K... fields) {
+        LettuceAssert.notNull(timestamp, "Timestamp must not be null");
+        return hexpireat(key, timestamp.getTime() / 1000, expireArgs, fields);
+    }
+
+    @Override
+    public Mono<Boolean> hexpireat(K key, Instant timestamp, K... fields) {
+        return hexpireat(key, timestamp, null, fields);
+    }
+
+    @Override
+    public Mono<Boolean> hexpireat(K key, Instant timestamp, ExpireArgs expireArgs, K... fields) {
+        LettuceAssert.notNull(timestamp, "Timestamp must not be null");
+        return hexpireat(key, timestamp.toEpochMilli() / 1000, expireArgs, fields);
+    }
+
     @Override
     public Mono<Long> expiretime(K key) {
         return createMono(() -> commandBuilder.expiretime(key));
     }
 
+    @Override
+    public Mono<Long> hexpiretime(K key, K... fields) {
+        return createMono(() -> commandBuilder.hexpiretime(key, fields));
+    }
+
     @Override
     public <T> Flux<T> fcall(String function, ScriptOutputType type, K... keys) {
         return createFlux(() -> commandBuilder.fcall(function, type, false, keys));
@@ -1556,6 +1618,11 @@ public Mono<Boolean> persist(K key) {
         return createMono(() -> commandBuilder.persist(key));
     }
 
+    @Override
+    public Mono<Boolean> hpersist(K key, K... fields) {
+        return createMono(() -> commandBuilder.hpersist(key, fields));
+    }
+
     @Override
     public Mono<Boolean> pexpire(K key, long milliseconds) {
         return pexpire(key, milliseconds, null);
diff --git a/src/main/java/io/lettuce/core/RedisCommandBuilder.java b/src/main/java/io/lettuce/core/RedisCommandBuilder.java
index 3d3d2be0be..143fc6cd89 100644
--- a/src/main/java/io/lettuce/core/RedisCommandBuilder.java
+++ b/src/main/java/io/lettuce/core/RedisCommandBuilder.java
@@ -19,19 +19,6 @@
  */
 package io.lettuce.core;
 
-import static io.lettuce.core.internal.LettuceStrings.*;
-import static io.lettuce.core.protocol.CommandKeyword.*;
-import static io.lettuce.core.protocol.CommandType.*;
-import static io.lettuce.core.protocol.CommandType.COPY;
-import static io.lettuce.core.protocol.CommandType.SAVE;
-
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
 import io.lettuce.core.Range.Boundary;
 import io.lettuce.core.XReadArgs.StreamOffset;
 import io.lettuce.core.codec.RedisCodec;
@@ -48,6 +35,19 @@
 import io.lettuce.core.protocol.CommandType;
 import io.lettuce.core.protocol.RedisCommand;
 
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static io.lettuce.core.internal.LettuceStrings.string;
+import static io.lettuce.core.protocol.CommandKeyword.*;
+import static io.lettuce.core.protocol.CommandType.*;
+import static io.lettuce.core.protocol.CommandType.COPY;
+import static io.lettuce.core.protocol.CommandType.SAVE;
+
 /**
  * @param <K>
  * @param <V>
@@ -978,6 +978,38 @@ Command<K, V, Boolean> expire(K key, long seconds, ExpireArgs expireArgs) {
         return createCommand(EXPIRE, new BooleanOutput<>(codec), args);
     }
 
+    Command<K, V, Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, K... fields) {
+        notNullKey(key);
+        notEmpty(fields);
+
+        CommandArgs<K, V> args = new CommandArgs<>(codec).addKey(key).add(seconds);
+
+        if (expireArgs != null) {
+            expireArgs.build(args);
+        }
+
+        args.add(fields.length);
+        args.addKeys(fields);
+
+        return createCommand(HEXPIRE, new BooleanOutput<>(codec), args);
+    }
+
+    Command<K, V, Boolean> hexpireat(K key, long seconds, ExpireArgs expireArgs, K... fields) {
+        notNullKey(key);
+        notEmpty(fields);
+
+        CommandArgs<K, V> args = new CommandArgs<>(codec).addKey(key).add(seconds);
+
+        if (expireArgs != null) {
+            expireArgs.build(args);
+        }
+
+        args.add(fields.length);
+        args.addKeys(fields);
+
+        return createCommand(HEXPIREAT, new BooleanOutput<>(codec), args);
+    }
+
     Command<K, V, Boolean> expireat(K key, long timestamp, ExpireArgs expireArgs) {
         notNullKey(key);
 
@@ -997,6 +1029,15 @@ Command<K, V, Long> expiretime(K key) {
         return createCommand(EXPIRETIME, new IntegerOutput<>(codec), args);
     }
 
+    Command<K, V, Long> hexpiretime(K key, K... fields) {
+        notNullKey(key);
+
+        CommandArgs<K, V> args = new CommandArgs<>(codec).addKey(key);
+        args.add(fields.length);
+        args.addKeys(fields);
+        return createCommand(HEXPIRETIME, new IntegerOutput<>(codec), args);
+    }
+
     Command<K, V, String> flushall() {
         return createCommand(FLUSHALL, new StatusOutput<>(codec));
     }
@@ -2043,6 +2084,16 @@ Command<K, V, Boolean> persist(K key) {
         return createCommand(PERSIST, new BooleanOutput<>(codec), key);
     }
 
+    Command<K, V, Boolean> hpersist(K key, K... fields) {
+        notNullKey(key);
+
+        CommandArgs<K, V> args = new CommandArgs<>(codec).addKey(key);
+        args.add(fields.length);
+        args.addKeys(fields);
+
+        return createCommand(HPERSIST, new BooleanOutput<>(codec), args);
+    }
+
     Command<K, V, Boolean> pexpire(K key, long milliseconds, ExpireArgs expireArgs) {
         notNullKey(key);
 
diff --git a/src/main/java/io/lettuce/core/api/async/RedisHashAsyncCommands.java b/src/main/java/io/lettuce/core/api/async/RedisHashAsyncCommands.java
index cc9b8b1489..9f514450fa 100644
--- a/src/main/java/io/lettuce/core/api/async/RedisHashAsyncCommands.java
+++ b/src/main/java/io/lettuce/core/api/async/RedisHashAsyncCommands.java
@@ -19,9 +19,7 @@
  */
 package io.lettuce.core.api.async;
 
-import java.util.List;
-import java.util.Map;
-
+import io.lettuce.core.ExpireArgs;
 import io.lettuce.core.KeyScanCursor;
 import io.lettuce.core.KeyValue;
 import io.lettuce.core.MapScanCursor;
@@ -33,6 +31,12 @@
 import io.lettuce.core.output.KeyValueStreamingChannel;
 import io.lettuce.core.output.ValueStreamingChannel;
 
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
 /**
  * Asynchronous executed commands for Hashes (Key-Value pairs).
  *
@@ -429,4 +433,152 @@ public interface RedisHashAsyncCommands<K, V> {
      * @return Long count of the keys.
      */
     RedisFuture<Long> hvals(ValueStreamingChannel<V> channel, K key);
+
+    /**
+     * Set the time to live (in seconds) for one or more fields, belonging to a certain key.
+     *
+     * @param key the key of the fields.
+     * @param seconds the seconds type: long.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    RedisFuture<Boolean> hexpire(K key, long seconds, K... fields);
+
+    /**
+     * Set the time to live (in seconds) for one or more fields, belonging to a certain key.
+     *
+     * @param key the key of the fields.
+     * @param seconds the seconds type: long.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    RedisFuture<Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key.
+     *
+     * @param key the key.
+     * @param seconds the TTL {@link Duration}
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    RedisFuture<Boolean> hexpire(K key, Duration seconds, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key.
+     *
+     * @param key the key.
+     * @param seconds the TTL {@link Duration}
+     * @param expireArgs the {@link ExpireArgs}.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    RedisFuture<Boolean> hexpire(K key, Duration seconds, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    RedisFuture<Boolean> hexpireat(K key, long timestamp, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    RedisFuture<Boolean> hexpireat(K key, long timestamp, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    RedisFuture<Boolean> hexpireat(K key, Date timestamp, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    RedisFuture<Boolean> hexpireat(K key, Date timestamp, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    RedisFuture<Boolean> hexpireat(K key, Instant timestamp, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    RedisFuture<Boolean> hexpireat(K key, Instant timestamp, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Get the time to live for one or more fields in as unix timestamp in seconds.
+     *
+     * @param key the key.
+     * @param fields one or more fields to get the TTL for.
+     * @return Long integer-reply in seconds, or a negative value in order to signal an error. The command returns {@code -1} if
+     *         the key exists but has no associated expiration time. The command returns {@code -2} if the key does not exist.
+     * @since 7.0
+     */
+    RedisFuture<Long> hexpiretime(K key, K... fields);
+
+    /**
+     * Remove the expiration from one or more fields.
+     *
+     * @param key the key.
+     * @param fields one or more fields to remove the TTL for.
+     * @return Boolean integer-reply specifically:
+     *
+     *         {@code true} if the timeout was removed. {@code false} if {@code key} does not exist or does not have an
+     *         associated timeout.
+     */
+    RedisFuture<Boolean> hpersist(K key, K... fields);
 }
diff --git a/src/main/java/io/lettuce/core/api/reactive/RedisHashReactiveCommands.java b/src/main/java/io/lettuce/core/api/reactive/RedisHashReactiveCommands.java
index 080087510a..e02fe5b80a 100644
--- a/src/main/java/io/lettuce/core/api/reactive/RedisHashReactiveCommands.java
+++ b/src/main/java/io/lettuce/core/api/reactive/RedisHashReactiveCommands.java
@@ -19,10 +19,7 @@
  */
 package io.lettuce.core.api.reactive;
 
-import java.util.Map;
-
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
+import io.lettuce.core.ExpireArgs;
 import io.lettuce.core.KeyScanCursor;
 import io.lettuce.core.KeyValue;
 import io.lettuce.core.MapScanCursor;
@@ -32,6 +29,13 @@
 import io.lettuce.core.output.KeyStreamingChannel;
 import io.lettuce.core.output.KeyValueStreamingChannel;
 import io.lettuce.core.output.ValueStreamingChannel;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Date;
+import java.util.Map;
 
 /**
  * Reactive executed commands for Hashes (Key-Value pairs).
@@ -451,4 +455,152 @@ public interface RedisHashReactiveCommands<K, V> {
      */
     @Deprecated
     Mono<Long> hvals(ValueStreamingChannel<V> channel, K key);
+
+    /**
+     * Set the time to live (in seconds) for one or more fields, belonging to a certain key.
+     *
+     * @param key the key of the fields.
+     * @param seconds the seconds type: long.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    Mono<Boolean> hexpire(K key, long seconds, K... fields);
+
+    /**
+     * Set the time to live (in seconds) for one or more fields, belonging to a certain key.
+     *
+     * @param key the key of the fields.
+     * @param seconds the seconds type: long.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    Mono<Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key.
+     *
+     * @param key the key.
+     * @param seconds the TTL {@link Duration}
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    Mono<Boolean> hexpire(K key, Duration seconds, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key.
+     *
+     * @param key the key.
+     * @param seconds the TTL {@link Duration}
+     * @param expireArgs the {@link ExpireArgs}.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    Mono<Boolean> hexpire(K key, Duration seconds, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    Mono<Boolean> hexpireat(K key, long timestamp, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    Mono<Boolean> hexpireat(K key, long timestamp, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    Mono<Boolean> hexpireat(K key, Date timestamp, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    Mono<Boolean> hexpireat(K key, Date timestamp, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    Mono<Boolean> hexpireat(K key, Instant timestamp, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    Mono<Boolean> hexpireat(K key, Instant timestamp, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Get the time to live for one or more fields in as unix timestamp in seconds.
+     *
+     * @param key the key.
+     * @param fields one or more fields to get the TTL for.
+     * @return Long integer-reply in seconds, or a negative value in order to signal an error. The command returns {@code -1} if
+     *         the key exists but has no associated expiration time. The command returns {@code -2} if the key does not exist.
+     * @since 7.0
+     */
+    Mono<Long> hexpiretime(K key, K... fields);
+
+    /**
+     * Remove the expiration from one or more fields.
+     *
+     * @param key the key.
+     * @param fields one or more fields to remove the TTL for.
+     * @return Boolean integer-reply specifically:
+     *
+     *         {@code true} if the timeout was removed. {@code false} if {@code key} does not exist or does not have an
+     *         associated timeout.
+     */
+    Mono<Boolean> hpersist(K key, K... fields);
 }
diff --git a/src/main/java/io/lettuce/core/api/sync/RedisHashCommands.java b/src/main/java/io/lettuce/core/api/sync/RedisHashCommands.java
index 816ec08227..ab41a1cafd 100644
--- a/src/main/java/io/lettuce/core/api/sync/RedisHashCommands.java
+++ b/src/main/java/io/lettuce/core/api/sync/RedisHashCommands.java
@@ -19,9 +19,7 @@
  */
 package io.lettuce.core.api.sync;
 
-import java.util.List;
-import java.util.Map;
-
+import io.lettuce.core.ExpireArgs;
 import io.lettuce.core.KeyScanCursor;
 import io.lettuce.core.KeyValue;
 import io.lettuce.core.MapScanCursor;
@@ -32,6 +30,12 @@
 import io.lettuce.core.output.KeyValueStreamingChannel;
 import io.lettuce.core.output.ValueStreamingChannel;
 
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
 /**
  * Synchronous executed commands for Hashes (Key-Value pairs).
  *
@@ -430,4 +434,152 @@ public interface RedisHashCommands<K, V> {
      * @return Long count of the keys.
      */
     Long hvals(ValueStreamingChannel<V> channel, K key);
+
+    /**
+     * Set the time to live (in seconds) for one or more fields, belonging to a certain key.
+     *
+     * @param key the key of the fields.
+     * @param seconds the seconds type: long.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    Boolean hexpire(K key, long seconds, K... fields);
+
+    /**
+     * Set the time to live (in seconds) for one or more fields, belonging to a certain key.
+     *
+     * @param key the key of the fields.
+     * @param seconds the seconds type: long.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    Boolean hexpire(K key, long seconds, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key.
+     *
+     * @param key the key.
+     * @param seconds the TTL {@link Duration}
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    Boolean hexpire(K key, Duration seconds, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key.
+     *
+     * @param key the key.
+     * @param seconds the TTL {@link Duration}
+     * @param expireArgs the {@link ExpireArgs}.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    Boolean hexpire(K key, Duration seconds, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    Boolean hexpireat(K key, long timestamp, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    Boolean hexpireat(K key, long timestamp, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    Boolean hexpireat(K key, Date timestamp, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    Boolean hexpireat(K key, Date timestamp, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    Boolean hexpireat(K key, Instant timestamp, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    Boolean hexpireat(K key, Instant timestamp, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Get the time to live for one or more fields in as unix timestamp in seconds.
+     *
+     * @param key the key.
+     * @param fields one or more fields to get the TTL for.
+     * @return Long integer-reply in seconds, or a negative value in order to signal an error. The command returns {@code -1} if
+     *         the key exists but has no associated expiration time. The command returns {@code -2} if the key does not exist.
+     * @since 7.0
+     */
+    Long hexpiretime(K key, K... fields);
+
+    /**
+     * Remove the expiration from one or more fields.
+     *
+     * @param key the key.
+     * @param fields one or more fields to remove the TTL for.
+     * @return Boolean integer-reply specifically:
+     *
+     *         {@code true} if the timeout was removed. {@code false} if {@code key} does not exist or does not have an
+     *         associated timeout.
+     */
+    Boolean hpersist(K key, K... fields);
 }
diff --git a/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionHashAsyncCommands.java b/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionHashAsyncCommands.java
index dd99fd23b0..442444c6ed 100644
--- a/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionHashAsyncCommands.java
+++ b/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionHashAsyncCommands.java
@@ -19,9 +19,7 @@
  */
 package io.lettuce.core.cluster.api.async;
 
-import java.util.List;
-import java.util.Map;
-
+import io.lettuce.core.ExpireArgs;
 import io.lettuce.core.KeyScanCursor;
 import io.lettuce.core.KeyValue;
 import io.lettuce.core.MapScanCursor;
@@ -32,6 +30,12 @@
 import io.lettuce.core.output.KeyValueStreamingChannel;
 import io.lettuce.core.output.ValueStreamingChannel;
 
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
 /**
  * Asynchronous executed commands on a node selection for Hashes (Key-Value pairs).
  *
@@ -428,4 +432,152 @@ public interface NodeSelectionHashAsyncCommands<K, V> {
      * @return Long count of the keys.
      */
     AsyncExecutions<Long> hvals(ValueStreamingChannel<V> channel, K key);
+
+    /**
+     * Set the time to live (in seconds) for one or more fields, belonging to a certain key.
+     *
+     * @param key the key of the fields.
+     * @param seconds the seconds type: long.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    AsyncExecutions<Boolean> hexpire(K key, long seconds, K... fields);
+
+    /**
+     * Set the time to live (in seconds) for one or more fields, belonging to a certain key.
+     *
+     * @param key the key of the fields.
+     * @param seconds the seconds type: long.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    AsyncExecutions<Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key.
+     *
+     * @param key the key.
+     * @param seconds the TTL {@link Duration}
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    AsyncExecutions<Boolean> hexpire(K key, Duration seconds, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key.
+     *
+     * @param key the key.
+     * @param seconds the TTL {@link Duration}
+     * @param expireArgs the {@link ExpireArgs}.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    AsyncExecutions<Boolean> hexpire(K key, Duration seconds, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    AsyncExecutions<Boolean> hexpireat(K key, long timestamp, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    AsyncExecutions<Boolean> hexpireat(K key, long timestamp, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    AsyncExecutions<Boolean> hexpireat(K key, Date timestamp, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    AsyncExecutions<Boolean> hexpireat(K key, Date timestamp, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    AsyncExecutions<Boolean> hexpireat(K key, Instant timestamp, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    AsyncExecutions<Boolean> hexpireat(K key, Instant timestamp, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Get the time to live for one or more fields in as unix timestamp in seconds.
+     *
+     * @param key the key.
+     * @param fields one or more fields to get the TTL for.
+     * @return Long integer-reply in seconds, or a negative value in order to signal an error. The command returns {@code -1} if
+     *         the key exists but has no associated expiration time. The command returns {@code -2} if the key does not exist.
+     * @since 7.0
+     */
+    AsyncExecutions<Long> hexpiretime(K key, K... fields);
+
+    /**
+     * Remove the expiration from one or more fields.
+     *
+     * @param key the key.
+     * @param fields one or more fields to remove the TTL for.
+     * @return Boolean integer-reply specifically:
+     *
+     *         {@code true} if the timeout was removed. {@code false} if {@code key} does not exist or does not have an
+     *         associated timeout.
+     */
+    AsyncExecutions<Boolean> hpersist(K key, K... fields);
 }
diff --git a/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionHashCommands.java b/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionHashCommands.java
index 4d9a3c694b..f2aeaf52b4 100644
--- a/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionHashCommands.java
+++ b/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionHashCommands.java
@@ -19,9 +19,7 @@
  */
 package io.lettuce.core.cluster.api.sync;
 
-import java.util.List;
-import java.util.Map;
-
+import io.lettuce.core.ExpireArgs;
 import io.lettuce.core.KeyScanCursor;
 import io.lettuce.core.KeyValue;
 import io.lettuce.core.MapScanCursor;
@@ -32,6 +30,12 @@
 import io.lettuce.core.output.KeyValueStreamingChannel;
 import io.lettuce.core.output.ValueStreamingChannel;
 
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
 /**
  * Synchronous executed commands on a node selection for Hashes (Key-Value pairs).
  *
@@ -428,4 +432,152 @@ public interface NodeSelectionHashCommands<K, V> {
      * @return Long count of the keys.
      */
     Executions<Long> hvals(ValueStreamingChannel<V> channel, K key);
+
+    /**
+     * Set the time to live (in seconds) for one or more fields, belonging to a certain key.
+     *
+     * @param key the key of the fields.
+     * @param seconds the seconds type: long.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    Executions<Boolean> hexpire(K key, long seconds, K... fields);
+
+    /**
+     * Set the time to live (in seconds) for one or more fields, belonging to a certain key.
+     *
+     * @param key the key of the fields.
+     * @param seconds the seconds type: long.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    Executions<Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key.
+     *
+     * @param key the key.
+     * @param seconds the TTL {@link Duration}
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    Executions<Boolean> hexpire(K key, Duration seconds, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key.
+     *
+     * @param key the key.
+     * @param seconds the TTL {@link Duration}
+     * @param expireArgs the {@link ExpireArgs}.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    Executions<Boolean> hexpire(K key, Duration seconds, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    Executions<Boolean> hexpireat(K key, long timestamp, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    Executions<Boolean> hexpireat(K key, long timestamp, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    Executions<Boolean> hexpireat(K key, Date timestamp, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    Executions<Boolean> hexpireat(K key, Date timestamp, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    Executions<Boolean> hexpireat(K key, Instant timestamp, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    Executions<Boolean> hexpireat(K key, Instant timestamp, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Get the time to live for one or more fields in as unix timestamp in seconds.
+     *
+     * @param key the key.
+     * @param fields one or more fields to get the TTL for.
+     * @return Long integer-reply in seconds, or a negative value in order to signal an error. The command returns {@code -1} if
+     *         the key exists but has no associated expiration time. The command returns {@code -2} if the key does not exist.
+     * @since 7.0
+     */
+    Executions<Long> hexpiretime(K key, K... fields);
+
+    /**
+     * Remove the expiration from one or more fields.
+     *
+     * @param key the key.
+     * @param fields one or more fields to remove the TTL for.
+     * @return Boolean integer-reply specifically:
+     *
+     *         {@code true} if the timeout was removed. {@code false} if {@code key} does not exist or does not have an
+     *         associated timeout.
+     */
+    Executions<Boolean> hpersist(K key, K... fields);
 }
diff --git a/src/main/java/io/lettuce/core/protocol/CommandType.java b/src/main/java/io/lettuce/core/protocol/CommandType.java
index 7a9d87524d..7207a50dab 100644
--- a/src/main/java/io/lettuce/core/protocol/CommandType.java
+++ b/src/main/java/io/lettuce/core/protocol/CommandType.java
@@ -46,7 +46,7 @@ public enum CommandType implements ProtocolKeyword {
 
     // Keys
 
-    COPY, DEL, DUMP, EXISTS, EXPIRE, EXPIREAT, EXPIRETIME, KEYS, MIGRATE, MOVE, OBJECT, PERSIST, PEXPIRE, PEXPIREAT, PEXPIRETIME, PTTL, RANDOMKEY, RENAME, RENAMENX, RESTORE, TOUCH, TTL, TYPE, SCAN, UNLINK,
+    COPY, DEL, DUMP, EXISTS, HEXPIRE, EXPIRE, HEXPIREAT, EXPIREAT, HEXPIRETIME, EXPIRETIME, KEYS, MIGRATE, MOVE, OBJECT, HPERSIST, PERSIST, PEXPIRE, PEXPIREAT, PEXPIRETIME, PTTL, RANDOMKEY, RENAME, RENAMENX, RESTORE, TOUCH, TTL, TYPE, SCAN, UNLINK,
 
     // String
 
diff --git a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisHashCoroutinesCommands.kt b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisHashCoroutinesCommands.kt
index 6ab7746601..34a4228f49 100644
--- a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisHashCoroutinesCommands.kt
+++ b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisHashCoroutinesCommands.kt
@@ -20,8 +20,17 @@
 
 package io.lettuce.core.api.coroutines
 
-import io.lettuce.core.*
+import io.lettuce.core.ExperimentalLettuceCoroutinesApi
+import io.lettuce.core.ExpireArgs
 import kotlinx.coroutines.flow.Flow
+import io.lettuce.core.KeyScanCursor
+import io.lettuce.core.KeyValue
+import io.lettuce.core.MapScanCursor
+import io.lettuce.core.ScanArgs
+import io.lettuce.core.ScanCursor
+import java.time.Duration
+import java.time.Instant
+import java.util.*
 
 /**
  * Coroutine executed commands for Hashes (Key-Value pairs).
@@ -298,5 +307,153 @@ interface RedisHashCoroutinesCommands<K : Any, V : Any> {
      */
     fun hvals(key: K): Flow<V>
 
+    /**
+     * Set the time to live (in seconds) for one or more fields, belonging to a certain key.
+     *
+     * @param key the key of the fields.
+     * @param seconds the seconds type: long.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: `true` if the timeout was set. `false` if `key` does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    suspend fun hexpire(key: K, seconds: Long, vararg fields: K): Boolean?
+
+    /**
+     * Set the time to live (in seconds) for one or more fields, belonging to a certain key.
+     *
+     * @param key the key of the fields.
+     * @param seconds the seconds type: long.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: `true` if the timeout was set. `false` if `key` does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    suspend fun hexpire(key: K, seconds: Long, expireArgs: ExpireArgs, vararg fields: K): Boolean?
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key.
+     *
+     * @param key the key.
+     * @param seconds the TTL [Duration]
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: `true` if the timeout was set. `false` if `key` does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    suspend fun hexpire(key: K, seconds: Duration, vararg fields: K): Boolean?
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key.
+     *
+     * @param key the key.
+     * @param seconds the TTL [Duration]
+     * @param expireArgs the [ExpireArgs].
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: `true` if the timeout was set. `false` if `key` does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    suspend fun hexpire(key: K, seconds: Duration, expireArgs: ExpireArgs, vararg fields: K): Boolean?
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: `true` if the timeout was set. `false` if `key` does not
+     *         exist or the timeout could not be set (see: `EXPIRE`).
+     * @since 7.0
+     */
+    suspend fun hexpireat(key: K, timestamp: Long, vararg fields: K): Boolean?
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: `true` if the timeout was set. `false` if `key` does not
+     *         exist or the timeout could not be set (see: `EXPIRE`).
+     * @since 7.0
+     */
+    suspend fun hexpireat(key: K, timestamp: Long, expireArgs: ExpireArgs, vararg fields: K): Boolean?
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: `true` if the timeout was set. `false` if `key` does not
+     *         exist or the timeout could not be set (see: `EXPIRE`).
+     * @since 7.0
+     */
+    suspend fun hexpireat(key: K, timestamp: Date, vararg fields: K): Boolean?
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: `true` if the timeout was set. `false` if `key` does not
+     *         exist or the timeout could not be set (see: `EXPIRE`).
+     * @since 7.0
+     */
+    suspend fun hexpireat(key: K, timestamp: Date, expireArgs: ExpireArgs, vararg fields: K): Boolean?
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: `true` if the timeout was set. `false` if `key` does not
+     *         exist or the timeout could not be set (see: `EXPIRE`).
+     * @since 7.0
+     */
+    suspend fun hexpireat(key: K, timestamp: Instant, vararg fields: K): Boolean?
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: `true` if the timeout was set. `false` if `key` does not
+     *         exist or the timeout could not be set (see: `EXPIRE`).
+     * @since 7.0
+     */
+    suspend fun hexpireat(key: K, timestamp: Instant, expireArgs: ExpireArgs, vararg fields: K): Boolean?
+
+    /**
+     * Get the time to live for one or more fields in as unix timestamp in seconds.
+     *
+     * @param key the key.
+     * @param fields one or more fields to get the TTL for.
+     * @return Long integer-reply in seconds, or a negative value in order to signal an error. The command returns `-1` if
+     *         the key exists but has no associated expiration time. The command returns `-2` if the key does not exist.
+     * @since 7.0
+     */
+    suspend fun hexpiretime(key: K, vararg fields: K): Long?
+
+    /**
+     * Remove the expiration from one or more fields.
+     *
+     * @param key the key.
+     * @param fields one or more fields to remove the TTL for.
+     * @return Boolean integer-reply specifically:
+     *
+     *         `true` if the timeout was removed. `false` if `key` does not exist or does not have an
+     *         associated timeout.
+     */
+    suspend fun hpersist(key: K, vararg fields: K): Boolean?
+
 }
 
diff --git a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisHashCoroutinesCommandsImpl.kt b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisHashCoroutinesCommandsImpl.kt
index ec1a488735..8a1d959e54 100644
--- a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisHashCoroutinesCommandsImpl.kt
+++ b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisHashCoroutinesCommandsImpl.kt
@@ -26,6 +26,9 @@ import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.toList
 import kotlinx.coroutines.reactive.asFlow
 import kotlinx.coroutines.reactive.awaitFirstOrNull
+import java.time.Duration
+import java.time.Instant
+import java.util.*
 
 
 /**
@@ -113,5 +116,60 @@ internal class RedisHashCoroutinesCommandsImpl<K : Any, V : Any>(internal val op
 
     override fun hvals(key: K): Flow<V> = ops.hvals(key).asFlow()
 
+    override suspend fun hexpire(key: K, seconds: Long, vararg fields: K): Boolean? =
+        ops.hexpire(key, seconds, *fields).awaitFirstOrNull()
+
+    override suspend fun hexpire(key: K, seconds: Long, expireArgs: ExpireArgs, vararg fields: K): Boolean? =
+        ops.hexpire(key, seconds, expireArgs, *fields).awaitFirstOrNull()
+
+    override suspend fun hexpire(key: K, seconds: Duration, vararg fields: K): Boolean? =
+        ops.hexpire(key, seconds, *fields).awaitFirstOrNull()
+
+    override suspend fun hexpire(
+        key: K,
+        seconds: Duration,
+        expireArgs: ExpireArgs,
+        vararg fields: K
+    ): Boolean? =
+        ops.hexpire(key, seconds, expireArgs, *fields).awaitFirstOrNull()
+
+    override suspend fun hexpireat(key: K, timestamp: Date, vararg fields: K): Boolean? =
+        ops.hexpireat(key, timestamp, *fields).awaitFirstOrNull()
+
+    override suspend fun hexpireat(
+        key: K,
+        timestamp: Long,
+        expireArgs: ExpireArgs,
+        vararg fields: K
+    ): Boolean? =
+        ops.hexpireat(key, timestamp, expireArgs, *fields).awaitFirstOrNull()
+
+    override suspend fun hexpireat(key: K, timestamp: Instant, vararg fields: K): Boolean? =
+        ops.hexpireat(key, timestamp, *fields).awaitFirstOrNull()
+
+    override suspend fun hexpireat(
+        key: K,
+        timestamp: Instant,
+        expireArgs: ExpireArgs,
+        vararg fields: K
+    ): Boolean? =
+        ops.hexpireat(key, timestamp, expireArgs, *fields).awaitFirstOrNull()
+
+    override suspend fun hexpireat(key: K, timestamp: Long, vararg fields: K): Boolean? =
+        ops.hexpireat(key, timestamp, *fields).awaitFirstOrNull()
+
+    override suspend fun hexpireat(
+        key: K,
+        timestamp: Date,
+        expireArgs: ExpireArgs,
+        vararg fields: K
+    ): Boolean? =
+        ops.hexpireat(key, timestamp, expireArgs, *fields).awaitFirstOrNull()
+
+    override suspend fun hexpiretime(key: K, vararg fields: K): Long? =
+        ops.hexpiretime(key).awaitFirstOrNull()
+
+    override suspend fun hpersist(key: K, vararg fields: K): Boolean? = ops.hpersist(key).awaitFirstOrNull()
+
 }
 
diff --git a/src/main/templates/io/lettuce/core/api/RedisHashCommands.java b/src/main/templates/io/lettuce/core/api/RedisHashCommands.java
index ddef1ce24f..96dfe525eb 100644
--- a/src/main/templates/io/lettuce/core/api/RedisHashCommands.java
+++ b/src/main/templates/io/lettuce/core/api/RedisHashCommands.java
@@ -428,4 +428,151 @@ public interface RedisHashCommands<K, V> {
      */
     Long hvals(ValueStreamingChannel<V> channel, K key);
 
+    /**
+     * Set the time to live (in seconds) for one or more fields, belonging to a certain key.
+     *
+     * @param key the key of the fields.
+     * @param seconds the seconds type: long.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    Boolean hexpire(K key, long seconds, K... fields);
+
+    /**
+     * Set the time to live (in seconds) for one or more fields, belonging to a certain key.
+     *
+     * @param key the key of the fields.
+     * @param seconds the seconds type: long.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    Boolean hexpire(K key, long seconds, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key.
+     *
+     * @param key the key.
+     * @param seconds the TTL {@link Duration}
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    Boolean hexpire(K key, Duration seconds, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key.
+     *
+     * @param key the key.
+     * @param seconds the TTL {@link Duration}
+     * @param expireArgs the {@link ExpireArgs}.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set.
+     * @since 7.0
+     */
+    Boolean hexpire(K key, Duration seconds, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    Boolean hexpireat(K key, long timestamp, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    Boolean hexpireat(K key, long timestamp, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    Boolean hexpireat(K key, Date timestamp, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    Boolean hexpireat(K key, Date timestamp, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    Boolean hexpireat(K key, Instant timestamp, K... fields);
+
+    /**
+     * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp.
+     *
+     * @param key the key.
+     * @param timestamp the timestamp type: posix time.
+     * @param expireArgs the expire arguments.
+     * @param fields one or more fields to set the TTL for.
+     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
+     *         exist or the timeout could not be set (see: {@code EXPIRE}).
+     * @since 7.0
+     */
+    Boolean hexpireat(K key, Instant timestamp, ExpireArgs expireArgs, K... fields);
+
+    /**
+     * Get the time to live for one or more fields in as unix timestamp in seconds.
+     *
+     * @param key the key.
+     * @param fields one or more fields to get the TTL for.
+     * @return Long integer-reply in seconds, or a negative value in order to signal an error. The command returns {@code -1} if
+     *         the key exists but has no associated expiration time. The command returns {@code -2} if the key does not exist.
+     * @since 7.0
+     */
+    Long hexpiretime(K key, K... fields);
+
+    /**
+     * Remove the expiration from one or more fields.
+     *
+     * @param key the key.
+     * @param fields one or more fields to remove the TTL for.
+     * @return Boolean integer-reply specifically:
+     *
+     *         {@code true} if the timeout was removed. {@code false} if {@code key} does not exist or does not have an
+     *         associated timeout.
+     */
+    Boolean hpersist(K key, K... fields);
 }
diff --git a/src/test/java/io/lettuce/core/RedisClientIntegrationTests.java b/src/test/java/io/lettuce/core/RedisClientIntegrationTests.java
index 2b78d3f99c..57eb8d2bbc 100644
--- a/src/test/java/io/lettuce/core/RedisClientIntegrationTests.java
+++ b/src/test/java/io/lettuce/core/RedisClientIntegrationTests.java
@@ -1,17 +1,5 @@
 package io.lettuce.core;
 
-import static org.assertj.core.api.Assertions.*;
-
-import java.lang.reflect.Field;
-import java.net.SocketAddress;
-import java.time.Duration;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-import org.junit.jupiter.api.Test;
-
 import io.lettuce.core.api.StatefulRedisConnection;
 import io.lettuce.core.event.command.CommandFailedEvent;
 import io.lettuce.core.event.command.CommandListener;
@@ -27,6 +15,17 @@
 import io.lettuce.test.resource.TestClientResources;
 import io.lettuce.test.settings.TestSettings;
 import io.netty.util.concurrent.EventExecutorGroup;
+import org.junit.jupiter.api.Test;
+
+import java.lang.reflect.Field;
+import java.net.SocketAddress;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import static org.assertj.core.api.Assertions.assertThat;
 
 /**
  * Integration tests for {@link RedisClient}.
@@ -138,7 +137,9 @@ void shouldPropagateCommandTimeoutToCommandListener() throws InterruptedExceptio
 
         assertThat(commandListener.started).hasSize(1);
         assertThat(commandListener.succeeded).isEmpty();
-        assertThat(commandListener.failed).hasSize(1).extracting(it -> it.getCommand().getType()).contains(CommandType.BLPOP);
+
+        Wait.untilTrue(() -> commandListener.failed.size() == 1);
+        assertThat(commandListener.failed).extracting(it -> it.getCommand().getType()).contains(CommandType.BLPOP);
 
         FastShutdown.shutdown(client);
     }
diff --git a/src/test/java/io/lettuce/core/RedisCommandBuilderUnitTests.java b/src/test/java/io/lettuce/core/RedisCommandBuilderUnitTests.java
index 9d2b676aae..01b5be2241 100644
--- a/src/test/java/io/lettuce/core/RedisCommandBuilderUnitTests.java
+++ b/src/test/java/io/lettuce/core/RedisCommandBuilderUnitTests.java
@@ -1,14 +1,14 @@
 package io.lettuce.core;
 
-import static org.assertj.core.api.Assertions.*;
-
-import java.nio.charset.StandardCharsets;
-
-import org.junit.jupiter.api.Test;
-
 import io.lettuce.core.codec.StringCodec;
 import io.lettuce.core.protocol.Command;
+import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
+import org.junit.jupiter.api.Test;
+
+import java.nio.charset.StandardCharsets;
+
+import static org.assertj.core.api.Assertions.assertThat;
 
 /**
  * Unit tests for {@link RedisCommandBuilder}.
@@ -16,6 +16,11 @@
  * @author Mark Paluch
  */
 class RedisCommandBuilderUnitTests {
+    public static final String MY_KEY = "hKey";
+    public static final String MY_FIELD1 = "hField1";
+    public static final String MY_FIELD2 = "hField2";
+    public static final String MY_FIELD3 = "hField3";
+
 
     RedisCommandBuilder<String, String> sut = new RedisCommandBuilder<>(StringCodec.UTF8);
 
@@ -29,4 +34,53 @@ void shouldCorrectlyConstructXreadgroup() {
                 .isEqualTo("stream");
     }
 
+    @Test
+    void shouldCorrectlyConstructHexpire() {
+
+        Command<String, String, ?> command =
+                sut.hexpire(MY_KEY, 1, ExpireArgs.Builder.nx(), MY_FIELD1, MY_FIELD2, MY_FIELD3);
+        ByteBuf buf = Unpooled.directBuffer();
+        command.encode(buf);
+
+        assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*8\r\n" + "$7\r\n" + "HEXPIRE\r\n" + "$4\r\n"
+                + "hKey\r\n" + "$1\r\n" + "1\r\n" + "$2\r\n" + "NX\r\n" + "$1\r\n" + "3\r\n" + "$7\r\n" + "hField1\r\n"
+                + "$7\r\n" + "hField2\r\n" + "$7\r\n" + "hField3\r\n");
+    }
+
+    @Test
+    void shouldCorrectlyConstructHexpireat() {
+
+        Command<String, String, ?> command =
+                sut.hexpireat(MY_KEY, 1, ExpireArgs.Builder.nx(), MY_FIELD1, MY_FIELD2, MY_FIELD3);
+        ByteBuf buf = Unpooled.directBuffer();
+        command.encode(buf);
+
+        assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*8\r\n" + "$9\r\n" + "HEXPIREAT\r\n" + "$4\r\n"
+                + "hKey\r\n" + "$1\r\n" + "1\r\n" + "$2\r\n" + "NX\r\n" + "$1\r\n" + "3\r\n" + "$7\r\n" + "hField1\r\n"
+                + "$7\r\n" + "hField2\r\n" + "$7\r\n" + "hField3\r\n");
+    }
+
+    @Test
+    void shouldCorrectlyConstructHexpiretime() {
+
+        Command<String, String, ?> command = sut.hexpiretime(MY_KEY, MY_FIELD1, MY_FIELD2, MY_FIELD3);
+        ByteBuf buf = Unpooled.directBuffer();
+        command.encode(buf);
+
+        assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*6\r\n" + "$11\r\n" + "HEXPIRETIME\r\n" + "$4\r\n"
+                + "hKey\r\n" + "$1\r\n" + "3\r\n" + "$7\r\n" + "hField1\r\n" + "$7\r\n" + "hField2\r\n" + "$7\r\n"
+                + "hField3\r\n");
+    }
+
+    @Test
+    void shouldCorrectlyConstructHpersist() {
+
+        Command<String, String, ?> command = sut.hpersist(MY_KEY, MY_FIELD1, MY_FIELD2, MY_FIELD3);
+        ByteBuf buf = Unpooled.directBuffer();
+        command.encode(buf);
+
+        assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*6\r\n" + "$8\r\n" + "HPERSIST\r\n" + "$4\r\n"
+                + "hKey\r\n" + "$1\r\n" + "3\r\n" + "$7\r\n" + "hField1\r\n" + "$7\r\n" + "hField2\r\n" + "$7\r\n"
+                + "hField3\r\n");
+    }
 }
diff --git a/src/test/java/io/lettuce/core/commands/HashCommandIntegrationTests.java b/src/test/java/io/lettuce/core/commands/HashCommandIntegrationTests.java
index e346b29128..b87102505d 100644
--- a/src/test/java/io/lettuce/core/commands/HashCommandIntegrationTests.java
+++ b/src/test/java/io/lettuce/core/commands/HashCommandIntegrationTests.java
@@ -19,24 +19,9 @@
  */
 package io.lettuce.core.commands;
 
-import static org.assertj.core.api.Assertions.*;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.inject.Inject;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestInstance;
-import org.junit.jupiter.api.extension.ExtendWith;
-
-import io.lettuce.core.KeyValue;
+import io.lettuce.core.ExpireArgs;
 import io.lettuce.core.KeyScanCursor;
+import io.lettuce.core.KeyValue;
 import io.lettuce.core.MapScanCursor;
 import io.lettuce.core.ScanArgs;
 import io.lettuce.core.ScanCursor;
@@ -47,6 +32,26 @@
 import io.lettuce.test.LettuceExtension;
 import io.lettuce.test.ListStreamingAdapter;
 import io.lettuce.test.condition.EnabledOnCommand;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import javax.inject.Inject;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.offset;
+import static org.awaitility.Awaitility.await;
 
 /**
  * Integration tests for {@link io.lettuce.core.api.sync.RedisHashCommands}.
@@ -58,6 +63,9 @@
 @ExtendWith(LettuceExtension.class)
 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
 public class HashCommandIntegrationTests extends TestSupport {
+    public static final String MY_KEY = "hKey";
+    public static final String MY_FIELD = "hField";
+    public static final String MY_VALUE = "hValue";
 
     private final RedisCommands<String, String> redis;
 
@@ -71,6 +79,13 @@ void setUp() {
         this.redis.flushall();
     }
 
+    @AfterEach
+    void tearDown() {
+        // resets the configuration settings to default, would not be needed once listpack is supported
+        assertThat(redis.configSet("hash-max-listpack-entries","512")).isEqualTo("OK");
+        assertThat(redis.configSet("set-max-listpack-value","64")).isEqualTo("OK");
+    }
+
     @Test
     void hdel() {
         assertThat(redis.hdel(key, "one")).isEqualTo(0);
@@ -541,6 +556,81 @@ void hscanNoValuesMatch() {
         assertThat(cursor.getKeys()).hasSize(11);
     }
 
+    @Test
+    @EnabledOnCommand("HEXPIRE")
+    void hexpire() {
+        // the below settings are required until the solution is able to support listpack entries
+        // see TODOs in https://github.com/redis/redis/pull/13172 for more details
+        assertThat(redis.configSet("hash-max-listpack-entries","0")).isEqualTo("OK");
+        assertThat(redis.configSet("set-max-listpack-value","0")).isEqualTo("OK");
+
+        assertThat(redis.hset(MY_KEY, MY_FIELD, MY_VALUE)).isTrue();
+        assertThat(redis.hexpire(MY_KEY, 1, MY_FIELD)).isTrue();
+
+        await().until(() -> redis.hget(MY_KEY, MY_FIELD) == null);
+    }
+
+    @Test
+    @EnabledOnCommand("HEXPIRE")
+    void hexpireExpireArgs() {
+        // the below settings are required until the solution is able to support listpack entries
+        // see TODOs in https://github.com/redis/redis/pull/13172 for more details
+        assertThat(redis.configSet("hash-max-listpack-entries","0")).isEqualTo("OK");
+        assertThat(redis.configSet("set-max-listpack-value","0")).isEqualTo("OK");
+
+        assertThat(redis.hset(MY_KEY, MY_FIELD, MY_VALUE)).isTrue();
+        assertThat(redis.hexpire(MY_KEY, Duration.ofSeconds(1), ExpireArgs.Builder.nx(), MY_FIELD)).isTrue();
+        assertThat(redis.hexpire(MY_KEY, Duration.ofSeconds(1), ExpireArgs.Builder.xx(), MY_FIELD)).isTrue();
+        assertThat(redis.hexpire(MY_KEY, Duration.ofSeconds(10), ExpireArgs.Builder.gt(), MY_FIELD)).isTrue();
+        assertThat(redis.hexpire(MY_KEY, Duration.ofSeconds(1), ExpireArgs.Builder.lt(), MY_FIELD)).isTrue();
+
+        await().until(() -> redis.hget(MY_KEY, MY_FIELD) == null);
+    }
+
+    @Test
+    @EnabledOnCommand("HEXPIREAT")
+    void hexpireat() {
+        // the below settings are required until the solution is able to support listpack entries
+        // see TODOs in https://github.com/redis/redis/pull/13172 for more details
+        assertThat(redis.configSet("hash-max-listpack-entries","0")).isEqualTo("OK");
+        assertThat(redis.configSet("set-max-listpack-value","0")).isEqualTo("OK");
+
+        assertThat(redis.hset(MY_KEY, MY_FIELD, MY_VALUE)).isTrue();
+        assertThat(redis.hexpireat(MY_KEY,Instant.now().plusSeconds(1) , MY_FIELD)).isTrue();
+
+        await().until(() -> redis.hget(MY_KEY, MY_FIELD) == null);
+    }
+
+    @Test
+    @EnabledOnCommand("HEXPIRETIME")
+    void hexpiretime() {
+        Date expiration = new Date(System.currentTimeMillis() + 10000);
+        // the below settings are required until the solution is able to support listpack entries
+        // see TODOs in https://github.com/redis/redis/pull/13172 for more details
+        assertThat(redis.configSet("hash-max-listpack-entries","0")).isEqualTo("OK");
+        assertThat(redis.configSet("set-max-listpack-value","0")).isEqualTo("OK");
+
+        assertThat(redis.hset(MY_KEY, MY_FIELD, MY_VALUE)).isTrue();
+        assertThat(redis.hexpireat(MY_KEY, expiration, MY_FIELD)).isTrue();
+
+        assertThat(redis.hexpiretime(MY_KEY, MY_FIELD)).isEqualTo(expiration.getTime() / 1000);
+    }
+
+    @Test
+    @EnabledOnCommand("HPERSIST")
+    void persist() {
+        // the below settings are required until the solution is able to support listpack entries
+        // see TODOs in https://github.com/redis/redis/pull/13172 for more details
+        assertThat(redis.configSet("hash-max-listpack-entries","0")).isEqualTo("OK");
+        assertThat(redis.configSet("set-max-listpack-value","0")).isEqualTo("OK");
+
+        assertThat(redis.hpersist(MY_KEY, MY_FIELD)).isFalse();
+        assertThat(redis.hset(MY_KEY, MY_FIELD, MY_VALUE)).isTrue();
+        assertThat(redis.hpersist(MY_KEY, MY_FIELD)).isFalse();
+        assertThat(redis.hexpire(MY_KEY, 1, MY_FIELD)).isTrue();
+        assertThat(redis.hpersist(MY_KEY, MY_FIELD)).isTrue();
+    }
+
     void setup100KeyValues(Map<String, String> expect) {
         for (int i = 0; i < 100; i++) {
             expect.put(key + i, value + 1);