diff --git a/src/libknot/rrtype/opt.c b/src/libknot/rrtype/opt.c
index d52fabbeef18b5c2e32b976b5e605ad0a778d233..9f2a9b878dc59a05c9b67d6e54348c446e68fffb 100644
--- a/src/libknot/rrtype/opt.c
+++ b/src/libknot/rrtype/opt.c
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -736,3 +736,50 @@ int knot_edns_client_subnet_get_addr(struct sockaddr_storage *addr,
 
 	return KNOT_EOK;
 }
+
+_public_
+size_t knot_edns_keepalive_size(uint16_t timeout)
+{
+	return (timeout == 0) ? sizeof(uint16_t) : 2 * sizeof(uint16_t);
+}
+
+_public_
+int knot_edns_keepalive_write(uint8_t *option, size_t option_len, uint16_t timeout)
+{
+	if (option == NULL) {
+		return KNOT_EINVAL;
+	}
+
+	wire_ctx_t wire = wire_ctx_init(option, option_len);
+	if (timeout == 0) {
+		wire_ctx_write_u16(&wire, 0);
+	} else {
+		wire_ctx_write_u16(&wire, 2);
+		wire_ctx_write_u16(&wire, timeout);
+	}
+
+	return wire.error;
+}
+
+_public_
+int knot_edns_keepalive_parse(uint16_t *timeout, const uint8_t *option, size_t option_len)
+{
+	if (timeout == NULL || option == NULL) {
+		return KNOT_EINVAL;
+	}
+
+	wire_ctx_t wire = wire_ctx_init_const(option, option_len);
+
+	uint16_t len = wire_ctx_read_u16(&wire);
+	if (len == 0) {
+		*timeout = 0;
+	} else {
+		*timeout = wire_ctx_read_u16(&wire);
+	}
+
+	if (wire.error != KNOT_EOK || wire_ctx_available(&wire) != 0) {
+		return KNOT_EMALF;
+	}
+
+	return KNOT_EOK;
+}
diff --git a/src/libknot/rrtype/opt.h b/src/libknot/rrtype/opt.h
index e87e70c6d29aef08adf0c397f3ce2427f08e42b4..81d280c7aee9b03c873648e51d56da7d9c183937 100644
--- a/src/libknot/rrtype/opt.h
+++ b/src/libknot/rrtype/opt.h
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -451,4 +451,35 @@ int knot_edns_client_subnet_set_addr(knot_edns_client_subnet_t *ecs,
 int knot_edns_client_subnet_get_addr(struct sockaddr_storage *addr,
                                      const knot_edns_client_subnet_t *ecs);
 
+/*!
+ * \brief Get size of the EDNS Keepalive option wire size.
+ *
+ * \param[in] timeout  EDNS TCP Keepalive timeout.
+ *
+ * \return Size of the EDNS option data.
+ */
+size_t knot_edns_keepalive_size(uint16_t timeout);
+
+/*!
+ * \brief Writes EDNS TCP Keepalive wire data.
+ *
+ * \param[out] option      EDNS option data buffer.
+ * \param[in]  option_len  EDNS option data buffer size.
+ * \param[in]  timeout     EDNS TCP Keepalive timeout.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_edns_keepalive_write(uint8_t *option, size_t option_len, uint16_t timeout);
+
+/*!
+ * \brief Parses EDNS TCP Keepalive wire data.
+ *
+ * \param[out] timeout     EDNS TCP Keepalive timeout.
+ * \param[in]  option      EDNS option data.
+ * \param[in]  option_len  EDNS option size.
+ *
+ * \return Error code, KNOT_EOK if successful.
+ */
+int knot_edns_keepalive_parse(uint16_t *timeout, const uint8_t *option, size_t option_len);
+
 /*! @} */