diff --git a/configure.ac b/configure.ac
index 76ca9c1..7a5a9ac 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1795,6 +1795,7 @@ AC_OUTPUT([
 	src/zabbix_server/odbc/Makefile
 	src/zabbix_server/scripts/Makefile
 	src/zabbix_server/preprocessor/Makefile
+	src/zabbix_server/availability/Makefile
 	src/zabbix_proxy/Makefile
 	src/zabbix_proxy/heart/Makefile
 	src/zabbix_proxy/housekeeper/Makefile
diff --git a/include/common.h b/include/common.h
index 1562cdf..4d134fe 100644
--- a/include/common.h
+++ b/include/common.h
@@ -500,36 +500,37 @@ zbx_group_status_type_t;
 const char	*get_program_type_string(unsigned char program_type);
 
 /* process type */
-#define ZBX_PROCESS_TYPE_POLLER		0
-#define ZBX_PROCESS_TYPE_UNREACHABLE	1
-#define ZBX_PROCESS_TYPE_IPMIPOLLER	2
-#define ZBX_PROCESS_TYPE_PINGER		3
-#define ZBX_PROCESS_TYPE_JAVAPOLLER	4
-#define ZBX_PROCESS_TYPE_HTTPPOLLER	5
-#define ZBX_PROCESS_TYPE_TRAPPER	6
-#define ZBX_PROCESS_TYPE_SNMPTRAPPER	7
-#define ZBX_PROCESS_TYPE_PROXYPOLLER	8
-#define ZBX_PROCESS_TYPE_ESCALATOR	9
-#define ZBX_PROCESS_TYPE_HISTSYNCER	10
-#define ZBX_PROCESS_TYPE_DISCOVERER	11
-#define ZBX_PROCESS_TYPE_ALERTER	12
-#define ZBX_PROCESS_TYPE_TIMER		13
-#define ZBX_PROCESS_TYPE_HOUSEKEEPER	14
-#define ZBX_PROCESS_TYPE_DATASENDER	15
-#define ZBX_PROCESS_TYPE_CONFSYNCER	16
-#define ZBX_PROCESS_TYPE_HEARTBEAT	17
-#define ZBX_PROCESS_TYPE_SELFMON	18
-#define ZBX_PROCESS_TYPE_VMWARE		19
-#define ZBX_PROCESS_TYPE_COLLECTOR	20
-#define ZBX_PROCESS_TYPE_LISTENER	21
-#define ZBX_PROCESS_TYPE_ACTIVE_CHECKS	22
-#define ZBX_PROCESS_TYPE_TASKMANAGER	23
-#define ZBX_PROCESS_TYPE_IPMIMANAGER	24
-#define ZBX_PROCESS_TYPE_ALERTMANAGER	25
-#define ZBX_PROCESS_TYPE_PREPROCMAN	26
-#define ZBX_PROCESS_TYPE_PREPROCESSOR	27
-#define ZBX_PROCESS_TYPE_COUNT		28	/* number of process types */
-#define ZBX_PROCESS_TYPE_UNKNOWN	255
+#define ZBX_PROCESS_TYPE_POLLER			0
+#define ZBX_PROCESS_TYPE_UNREACHABLE		1
+#define ZBX_PROCESS_TYPE_IPMIPOLLER		2
+#define ZBX_PROCESS_TYPE_PINGER			3
+#define ZBX_PROCESS_TYPE_JAVAPOLLER		4
+#define ZBX_PROCESS_TYPE_HTTPPOLLER		5
+#define ZBX_PROCESS_TYPE_TRAPPER		6
+#define ZBX_PROCESS_TYPE_SNMPTRAPPER		7
+#define ZBX_PROCESS_TYPE_PROXYPOLLER		8
+#define ZBX_PROCESS_TYPE_ESCALATOR		9
+#define ZBX_PROCESS_TYPE_HISTSYNCER		10
+#define ZBX_PROCESS_TYPE_DISCOVERER		11
+#define ZBX_PROCESS_TYPE_ALERTER		12
+#define ZBX_PROCESS_TYPE_TIMER			13
+#define ZBX_PROCESS_TYPE_HOUSEKEEPER		14
+#define ZBX_PROCESS_TYPE_DATASENDER		15
+#define ZBX_PROCESS_TYPE_CONFSYNCER		16
+#define ZBX_PROCESS_TYPE_HEARTBEAT		17
+#define ZBX_PROCESS_TYPE_SELFMON		18
+#define ZBX_PROCESS_TYPE_VMWARE			19
+#define ZBX_PROCESS_TYPE_COLLECTOR		20
+#define ZBX_PROCESS_TYPE_LISTENER		21
+#define ZBX_PROCESS_TYPE_ACTIVE_CHECKS		22
+#define ZBX_PROCESS_TYPE_TASKMANAGER		23
+#define ZBX_PROCESS_TYPE_IPMIMANAGER		24
+#define ZBX_PROCESS_TYPE_ALERTMANAGER		25
+#define ZBX_PROCESS_TYPE_PREPROCMAN		26
+#define ZBX_PROCESS_TYPE_PREPROCESSOR		27
+#define ZBX_PROCESS_TYPE_AVAILABILITY_SYNCER	28
+#define ZBX_PROCESS_TYPE_COUNT			29	/* number of process types */
+#define ZBX_PROCESS_TYPE_UNKNOWN		255
 const char	*get_process_type_string(unsigned char process_type);
 int		get_process_type_by_name(const char *proc_type_str);
 
@@ -594,6 +595,8 @@ zbx_maintenance_type_t;
 #define HOST_AVAILABLE_UNKNOWN		0
 #define HOST_AVAILABLE_TRUE		1
 #define HOST_AVAILABLE_FALSE		2
+#define HOST_AVAILABLE_PARTIAL		3
+#define HOST_AVAILABLE_UNSET		4
 
 /* trigger statuses */
 #define TRIGGER_STATUS_ENABLED		0
diff --git a/include/db.h b/include/db.h
index 1bec8aa..cc42919 100644
--- a/include/db.h
+++ b/include/db.h
@@ -663,49 +663,6 @@ void	zbx_db_insert_clean(zbx_db_insert_t *self);
 void	zbx_db_insert_autoincrement(zbx_db_insert_t *self, const char *field_name);
 int	zbx_db_get_database_type(void);
 
-/* agent (ZABBIX, SNMP, IPMI, JMX) availability data */
-typedef struct
-{
-	/* flags specifying which fields are set, see ZBX_FLAGS_AGENT_STATUS_* defines */
-	unsigned char	flags;
-
-	/* agent availability fields */
-	unsigned char	available;
-	char		*error;
-	int		errors_from;
-	int		disable_until;
-}
-zbx_agent_availability_t;
-
-#define ZBX_FLAGS_AGENT_STATUS_NONE		0x00000000
-#define ZBX_FLAGS_AGENT_STATUS_AVAILABLE	0x00000001
-#define ZBX_FLAGS_AGENT_STATUS_ERROR		0x00000002
-#define ZBX_FLAGS_AGENT_STATUS_ERRORS_FROM	0x00000004
-#define ZBX_FLAGS_AGENT_STATUS_DISABLE_UNTIL	0x00000008
-
-#define ZBX_FLAGS_AGENT_STATUS		(ZBX_FLAGS_AGENT_STATUS_AVAILABLE |	\
-					ZBX_FLAGS_AGENT_STATUS_ERROR |		\
-					ZBX_FLAGS_AGENT_STATUS_ERRORS_FROM |	\
-					ZBX_FLAGS_AGENT_STATUS_DISABLE_UNTIL)
-
-#define ZBX_AGENT_ZABBIX	(INTERFACE_TYPE_AGENT - 1)
-#define ZBX_AGENT_SNMP		(INTERFACE_TYPE_SNMP - 1)
-#define ZBX_AGENT_IPMI		(INTERFACE_TYPE_IPMI - 1)
-#define ZBX_AGENT_JMX		(INTERFACE_TYPE_JMX - 1)
-#define ZBX_AGENT_UNKNOWN 	255
-#define ZBX_AGENT_MAX		INTERFACE_TYPE_COUNT
-
-typedef struct
-{
-	zbx_uint64_t			hostid;
-
-	zbx_agent_availability_t	agents[ZBX_AGENT_MAX];
-}
-zbx_host_availability_t;
-
-
-int	zbx_sql_add_host_availability(char **sql, size_t *sql_alloc, size_t *sql_offset,
-		const zbx_host_availability_t *ha);
 int	DBget_user_by_active_session(const char *sessionid, zbx_user_t *user);
 
 typedef struct
diff --git a/include/dbcache.h b/include/dbcache.h
index 3ecbe5b..63abce1 100644
--- a/include/dbcache.h
+++ b/include/dbcache.h
@@ -104,22 +104,10 @@ typedef struct
 	unsigned char	maintenance_status;
 	unsigned char	maintenance_type;
 	int		maintenance_from;
-	int		errors_from;
-	unsigned char	available;
-	int		disable_until;
-	int		snmp_errors_from;
-	unsigned char	snmp_available;
-	int		snmp_disable_until;
-	int		ipmi_errors_from;
-	unsigned char	ipmi_available;
-	int		ipmi_disable_until;
 	signed char	ipmi_authtype;
 	unsigned char	ipmi_privilege;
 	char		ipmi_username[HOST_IPMI_USERNAME_LEN_MAX];
 	char		ipmi_password[HOST_IPMI_PASSWORD_LEN_MAX];
-	int		jmx_errors_from;
-	unsigned char	jmx_available;
-	int		jmx_disable_until;
 	char		inventory_mode;
 	unsigned char	status;
 	unsigned char	tls_connect;
@@ -130,15 +118,30 @@ typedef struct
 	char		tls_psk_identity[HOST_TLS_PSK_IDENTITY_LEN_MAX];
 	char		tls_psk[HOST_TLS_PSK_LEN_MAX];
 #endif
-	char		error[HOST_ERROR_LEN_MAX];
-	char		snmp_error[HOST_ERROR_LEN_MAX];
-	char		ipmi_error[HOST_ERROR_LEN_MAX];
-	char		jmx_error[HOST_ERROR_LEN_MAX];
 }
 DC_HOST;
 
 typedef struct
 {
+	unsigned char	available;
+	char		*error;
+	int		errors_from;
+	int		disable_until;
+}
+zbx_agent_status_t;
+
+typedef struct
+{
+	zbx_uint64_t	hostid;
+	unsigned char	type;
+	unsigned int	flags;
+	unsigned char	available;
+	char		*error;
+}
+zbx_agent_status_update_t;
+
+typedef struct
+{
 	DC_HOST			host;
 	DC_INTERFACE		interface;
 	zbx_uint64_t		itemid;
@@ -197,6 +200,7 @@ typedef struct
 	char			ssl_key_file_orig[ITEM_SSL_KEY_FILE_LEN_MAX], *ssl_key_file;
 	char			ssl_key_password_orig[ITEM_SSL_KEY_PASSWORD_LEN_MAX], *ssl_key_password;
 	char			*error;
+	zbx_agent_status_t	agent;
 }
 DC_ITEM;
 
@@ -664,11 +668,8 @@ size_t	DCget_psk_by_identity(const unsigned char *psk_identity, unsigned char *p
 void	DCget_user_macro(const zbx_uint64_t *hostids, int host_num, const char *macro, char **replace_to);
 char	*DCexpression_expand_user_macros(const char *expression, char **error);
 
-int	DChost_activate(zbx_uint64_t hostid, unsigned char agent_type, const zbx_timespec_t *ts,
-		zbx_agent_availability_t *in, zbx_agent_availability_t *out);
-
-int	DChost_deactivate(zbx_uint64_t hostid, unsigned char agent, const zbx_timespec_t *ts,
-		zbx_agent_availability_t *in, zbx_agent_availability_t *out, const char *error);
+unsigned int	zbx_dc_item_activate(const DC_ITEM *item);
+unsigned int	zbx_dc_item_deactivate(const DC_ITEM *item, const zbx_timespec_t *ts, const char *error_msg);
 
 #define ZBX_QUEUE_FROM_DEFAULT	6	/* default lower limit for delay (in seconds) */
 #define ZBX_QUEUE_TO_INFINITY	-1	/* no upper limit for delay */
@@ -700,25 +701,14 @@ void	DCget_hosts_by_functionids(const zbx_vector_uint64_t *functionids, zbx_hash
 void	zbx_config_get(zbx_config_t *cfg, zbx_uint64_t flags);
 void	zbx_config_clean(zbx_config_t *cfg);
 
-int	DCset_hosts_availability(zbx_vector_ptr_t *availabilities);
-
-int	DCreset_hosts_availability(zbx_vector_ptr_t *hosts);
-void	DCupdate_hosts_availability(void);
+void	zbx_dc_reset_proxy_hosts_availability();
 
 void	zbx_dc_get_actions_eval(zbx_vector_ptr_t *actions, zbx_hashset_t *uniq_conditions, unsigned char opflags);
 void	zbx_action_eval_free(zbx_action_eval_t *action);
 void	zbx_db_condition_clean(DB_CONDITION *condition);
 void	zbx_conditions_eval_clean(zbx_hashset_t *uniq_conditions);
 
-int	DCget_hosts_availability(zbx_vector_ptr_t *hosts, int *ts);
-void	DCtouch_hosts_availability(const zbx_vector_uint64_t *hostids);
-
-void	zbx_host_availability_init(zbx_host_availability_t *availability, zbx_uint64_t hostid);
-void	zbx_host_availability_clean(zbx_host_availability_t *availability);
-void	zbx_host_availability_free(zbx_host_availability_t *availability);
-int	zbx_host_availability_is_set(const zbx_host_availability_t *ha);
-
-void	zbx_set_availability_diff_ts(int ts);
+void	zbx_dc_refresh_hosts_availability(const zbx_vector_uint64_t *hostids);
 
 void	zbx_dc_correlation_rules_init(zbx_correlation_rules_t *rules);
 void	zbx_dc_correlation_rules_clean(zbx_correlation_rules_t *rules);
@@ -782,4 +772,29 @@ void	zbx_dc_get_trigger_dependencies(const zbx_vector_uint64_t *triggerids, zbx_
 
 void	zbx_dc_reschedule_items(const zbx_vector_uint64_t *itemids, int now, zbx_uint64_t *proxy_hostids);
 
+int	zbx_dc_get_host_availability_updates(zbx_vector_ptr_t *availability);
+void	zbx_dc_get_host_availability(zbx_uint64_t hostid, zbx_agent_status_t *agents);
+void	zbx_dc_clean_host_availability(zbx_agent_status_t *agents);
+void	zbx_agent_status_update_free(void *data);
+void	zbx_refresh_host_availability(const zbx_vector_ptr_t *updates);
+void	zbx_dc_update_proxy_host_availability(const zbx_vector_ptr_t *updates);
+
+#define ZBX_AGENT_STATUS_NONE		0x00000000
+#define ZBX_AGENT_STATUS_AVAILABLE	0x00000001
+#define ZBX_AGENT_STATUS_ERROR		0x00000002
+#define ZBX_AGENT_STATUS_ERRORS_FROM	0x00000004
+#define ZBX_AGENT_STATUS_DISABLE_UNTIL	0x00000008
+
+#define ZBX_AGENT_STATUS		(ZBX_AGENT_STATUS_AVAILABLE |	\
+					ZBX_AGENT_STATUS_ERROR |	\
+					ZBX_AGENT_STATUS_ERRORS_FROM |	\
+					ZBX_AGENT_STATUS_DISABLE_UNTIL)
+
+#define ZBX_AGENT_ZABBIX	(INTERFACE_TYPE_AGENT - 1)
+#define ZBX_AGENT_SNMP		(INTERFACE_TYPE_SNMP - 1)
+#define ZBX_AGENT_IPMI		(INTERFACE_TYPE_IPMI - 1)
+#define ZBX_AGENT_JMX		(INTERFACE_TYPE_JMX - 1)
+#define ZBX_AGENT_UNKNOWN 	255
+#define ZBX_AGENT_MAX		INTERFACE_TYPE_COUNT
+
 #endif
diff --git a/include/proxy.h b/include/proxy.h
index 447aa28..17f9cc8 100644
--- a/include/proxy.h
+++ b/include/proxy.h
@@ -42,7 +42,7 @@ void	update_proxy_lastaccess(const zbx_uint64_t hostid, time_t last_access);
 int	get_proxyconfig_data(zbx_uint64_t proxy_hostid, struct zbx_json *j, char **error);
 void	process_proxyconfig(struct zbx_json_parse *jp_data);
 
-int	get_host_availability_data(struct zbx_json *j, int *ts);
+int	get_host_availability_data(struct zbx_json *j, zbx_vector_ptr_t *updates);
 int	process_host_availability(struct zbx_json_parse *jp_data, char **error);
 
 int	proxy_get_hist_data(struct zbx_json *j, zbx_uint64_t *lastid, int *more);
diff --git a/src/libs/zbxcommon/str.c b/src/libs/zbxcommon/str.c
index d9cf872..8049900 100644
--- a/src/libs/zbxcommon/str.c
+++ b/src/libs/zbxcommon/str.c
@@ -1973,6 +1973,8 @@ const char	*get_process_type_string(unsigned char proc_type)
 			return "preprocessing manager";
 		case ZBX_PROCESS_TYPE_PREPROCESSOR:
 			return "preprocessing worker";
+		case ZBX_PROCESS_TYPE_AVAILABILITY_SYNCER:
+			return "availability syncer";
 	}
 
 	THIS_SHOULD_NEVER_HAPPEN;
diff --git a/src/libs/zbxdbcache/dbcache.c b/src/libs/zbxdbcache/dbcache.c
index f28720c..cde8cf2 100644
--- a/src/libs/zbxdbcache/dbcache.c
+++ b/src/libs/zbxdbcache/dbcache.c
@@ -4269,6 +4269,7 @@ zbx_uint64_t	DCget_nextid(const char *table_name, int num)
  *          on interfaces without enabled items                               *
  *                                                                            *
  ******************************************************************************/
+#ifdef DUMMY
 void	DCupdate_hosts_availability(void)
 {
 	const char		*__function_name = "DCupdate_hosts_availability";
@@ -4312,3 +4313,4 @@ out:
 
 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
 }
+#endif
diff --git a/src/libs/zbxdbcache/dbconfig.c b/src/libs/zbxdbcache/dbconfig.c
index ffe05ba..1f65542 100644
--- a/src/libs/zbxdbcache/dbconfig.c
+++ b/src/libs/zbxdbcache/dbconfig.c
@@ -288,8 +288,6 @@ static zbx_uint64_t	get_item_nextcheck_seed(zbx_uint64_t itemid, zbx_uint64_t in
 	return itemid;
 }
 
-static int	DCget_disable_until(const ZBX_DC_ITEM *item, const ZBX_DC_HOST *host);
-
 #define ZBX_ITEM_COLLECTED		0x01	/* force item rescheduling after new value collection */
 #define ZBX_HOST_UNREACHABLE		0x02
 #define ZBX_ITEM_KEY_CHANGED		0x04
@@ -410,62 +408,6 @@ static void	DCitem_poller_type_update(ZBX_DC_ITEM *dc_item, const ZBX_DC_HOST *d
 	}
 }
 
-static int	DCget_disable_until(const ZBX_DC_ITEM *item, const ZBX_DC_HOST *host)
-{
-	switch (item->type)
-	{
-		case ITEM_TYPE_ZABBIX:
-			if (0 != host->errors_from)
-				return host->disable_until;
-			break;
-		case ITEM_TYPE_SNMPv1:
-		case ITEM_TYPE_SNMPv2c:
-		case ITEM_TYPE_SNMPv3:
-			if (0 != host->snmp_errors_from)
-				return host->snmp_disable_until;
-			break;
-		case ITEM_TYPE_IPMI:
-			if (0 != host->ipmi_errors_from)
-				return host->ipmi_disable_until;
-			break;
-		case ITEM_TYPE_JMX:
-			if (0 != host->jmx_errors_from)
-				return host->jmx_disable_until;
-			break;
-		default:
-			/* nothing to do */;
-	}
-
-	return 0;
-}
-
-static void	DCincrease_disable_until(const ZBX_DC_ITEM *item, ZBX_DC_HOST *host, int now)
-{
-	switch (item->type)
-	{
-		case ITEM_TYPE_ZABBIX:
-			if (0 != host->errors_from)
-				host->disable_until = now + CONFIG_TIMEOUT;
-			break;
-		case ITEM_TYPE_SNMPv1:
-		case ITEM_TYPE_SNMPv2c:
-		case ITEM_TYPE_SNMPv3:
-			if (0 != host->snmp_errors_from)
-				host->snmp_disable_until = now + CONFIG_TIMEOUT;
-			break;
-		case ITEM_TYPE_IPMI:
-			if (0 != host->ipmi_errors_from)
-				host->ipmi_disable_until = now + CONFIG_TIMEOUT;
-			break;
-		case ITEM_TYPE_JMX:
-			if (0 != host->jmx_errors_from)
-				host->jmx_disable_until = now + CONFIG_TIMEOUT;
-			break;
-		default:
-			/* nothing to do */;
-	}
-}
-
 /******************************************************************************
  *                                                                            *
  * Function: DCfind_id                                                        *
@@ -1012,7 +954,7 @@ static void	DCsync_hosts(zbx_dbsync_t *sync)
 
 		ZBX_STR2UINT64(hostid, row[0]);
 		ZBX_DBROW2UINT64(proxy_hostid, row[1]);
-		ZBX_STR2UCHAR(status, row[22]);
+		ZBX_STR2UCHAR(status, row[14]);
 
 		host = (ZBX_DC_HOST *)DCfind_id(&config->hosts, hostid, sizeof(ZBX_DC_HOST), &found);
 
@@ -1071,10 +1013,10 @@ static void	DCsync_hosts(zbx_dbsync_t *sync)
 		/* store new information in host structure */
 
 		DCstrpool_replace(found, &host->host, row[2]);
-		DCstrpool_replace(found, &host->name, row[23]);
+		DCstrpool_replace(found, &host->name, row[15]);
 #if defined(HAVE_POLARSSL) || defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
-		DCstrpool_replace(found, &host->tls_issuer, row[31]);
-		DCstrpool_replace(found, &host->tls_subject, row[32]);
+		DCstrpool_replace(found, &host->tls_issuer, row[23]);
+		DCstrpool_replace(found, &host->tls_subject, row[24]);
 
 		/* maintain 'config->psks' in configuration cache */
 
@@ -1143,7 +1085,7 @@ static void	DCsync_hosts(zbx_dbsync_t *sync)
 
 		psk_owner = NULL;
 
-		if ('\0' == *row[33] || '\0' == *row[34])	/* new PSKid or value empty */
+		if ('\0' == *row[25] || '\0' == *row[26])	/* new PSKid or value empty */
 		{
 			/* In case of "impossible" errors ("PSK value without identity" or "PSK identity without */
 			/* value") assume empty PSK identity and value. These errors should have been prevented */
@@ -1174,14 +1116,14 @@ static void	DCsync_hosts(zbx_dbsync_t *sync)
 
 		/* new PSKid and value non-empty */
 
-		zbx_strlower(row[34]);
+		zbx_strlower(row[26]);
 
 		if (1 == found && NULL != host->tls_dc_psk)	/* 'host' record has non-empty PSK */
 		{
-			if (0 == strcmp(host->tls_dc_psk->tls_psk_identity, row[33]))	/* new PSKid same as */
+			if (0 == strcmp(host->tls_dc_psk->tls_psk_identity, row[25]))	/* new PSKid same as */
 											/* old PSKid */
 			{
-				if (0 != strcmp(host->tls_dc_psk->tls_psk, row[34]))	/* new PSK value */
+				if (0 != strcmp(host->tls_dc_psk->tls_psk, row[26]))	/* new PSK value */
 											/* differs from old */
 				{
 					if (NULL == (psk_owner = (zbx_ptr_pair_t *)zbx_hashset_search(&psk_owners,
@@ -1218,17 +1160,17 @@ static void	DCsync_hosts(zbx_dbsync_t *sync)
 
 		/* new PSK identity already stored? */
 
-		psk_i_local.tls_psk_identity = row[33];
+		psk_i_local.tls_psk_identity = row[25];
 
 		if (NULL != (psk_i = (ZBX_DC_PSK *)zbx_hashset_search(&config->psks, &psk_i_local)))
 		{
 			/* new PSKid already in psks hashset */
 
-			if (0 != strcmp(psk_i->tls_psk, row[34]))	/* PSKid stored but PSK value is different */
+			if (0 != strcmp(psk_i->tls_psk, row[26]))	/* PSKid stored but PSK value is different */
 			{
 				if (NULL == (psk_owner = (zbx_ptr_pair_t *)zbx_hashset_search(&psk_owners, &psk_i->tls_psk_identity)))
 				{
-					DCstrpool_replace(1, &psk_i->tls_psk, row[34]);
+					DCstrpool_replace(1, &psk_i->tls_psk, row[26]);
 				}
 				else
 				{
@@ -1245,8 +1187,8 @@ static void	DCsync_hosts(zbx_dbsync_t *sync)
 
 		/* insert new PSKid and value into psks hashset */
 
-		DCstrpool_replace(0, &psk_i_local.tls_psk_identity, row[33]);
-		DCstrpool_replace(0, &psk_i_local.tls_psk, row[34]);
+		DCstrpool_replace(0, &psk_i_local.tls_psk_identity, row[25]);
+		DCstrpool_replace(0, &psk_i_local.tls_psk, row[26]);
 		psk_i_local.refcount = 1;
 		host->tls_dc_psk = zbx_hashset_insert(&config->psks, &psk_i_local, sizeof(ZBX_DC_PSK));
 done:
@@ -1263,8 +1205,8 @@ done:
 			}
 		}
 #endif
-		ZBX_STR2UCHAR(host->tls_connect, row[29]);
-		ZBX_STR2UCHAR(host->tls_accept, row[30]);
+		ZBX_STR2UCHAR(host->tls_connect, row[21]);
+		ZBX_STR2UCHAR(host->tls_accept, row[22]);
 
 		if (0 == found)
 		{
@@ -1274,32 +1216,21 @@ done:
 			host->data_expected_from = now;
 			host->update_items = 0;
 
-			host->errors_from = atoi(row[10]);
 			host->available = (unsigned char)atoi(row[11]);
-			host->disable_until = atoi(row[12]);
-			host->snmp_errors_from = atoi(row[13]);
-			host->snmp_available = (unsigned char)atoi(row[14]);
-			host->snmp_disable_until = atoi(row[15]);
-			host->ipmi_errors_from = atoi(row[16]);
-			host->ipmi_available = (unsigned char)atoi(row[17]);
-			host->ipmi_disable_until = atoi(row[18]);
-			host->jmx_errors_from = atoi(row[19]);
-			host->jmx_available = (unsigned char)atoi(row[20]);
-			host->jmx_disable_until = atoi(row[21]);
-			host->availability_ts = now;
-
-			DCstrpool_replace(0, &host->error, row[25]);
-			DCstrpool_replace(0, &host->snmp_error, row[26]);
-			DCstrpool_replace(0, &host->ipmi_error, row[27]);
-			DCstrpool_replace(0, &host->jmx_error, row[28]);
+			host->snmp_available = (unsigned char)atoi(row[12]);
+			host->ipmi_available = (unsigned char)atoi(row[13]);
+			host->jmx_available = (unsigned char)atoi(row[14]);
+
+			DCstrpool_replace(0, &host->error, row[17]);
+			DCstrpool_replace(0, &host->snmp_error, row[18]);
+			DCstrpool_replace(0, &host->ipmi_error, row[19]);
+			DCstrpool_replace(0, &host->jmx_error, row[20]);
 
 			host->items_num = 0;
 			host->snmp_items_num = 0;
 			host->ipmi_items_num = 0;
 			host->jmx_items_num = 0;
 
-			host->reset_availability = 0;
-
 			zbx_vector_ptr_create_ext(&host->interfaces_v, __config_mem_malloc_func,
 					__config_mem_realloc_func, __config_mem_free_func);
 		}
@@ -1307,10 +1238,6 @@ done:
 		{
 			if (HOST_STATUS_MONITORED == status && HOST_STATUS_MONITORED != host->status)
 				host->data_expected_from = now;
-
-			/* reset host status if host proxy assignment has been changed */
-			if (proxy_hostid != host->proxy_hostid)
-				host->reset_availability = 1;
 		}
 
 		host->proxy_hostid = proxy_hostid;
@@ -1367,12 +1294,12 @@ done:
 				proxy->timediff = 0;
 				proxy->location = ZBX_LOC_NOWHERE;
 				proxy->version = 0;
-				proxy->lastaccess = atoi(row[24]);
+				proxy->lastaccess = atoi(row[16]);
 				proxy->last_cfg_error_time = 0;
 			}
 
-			proxy->auto_compress = atoi(row[32 + ZBX_HOST_TLS_OFFSET]);
-			DCstrpool_replace(found, &proxy->proxy_address, row[31 + ZBX_HOST_TLS_OFFSET]);
+			proxy->auto_compress = atoi(row[24 + ZBX_HOST_TLS_OFFSET]);
+			DCstrpool_replace(found, &proxy->proxy_address, row[23 + ZBX_HOST_TLS_OFFSET]);
 
 			if (HOST_STATUS_PROXY_PASSIVE == status && (0 == found || status != host->status))
 			{
@@ -2257,7 +2184,140 @@ static void	dc_host_update_agent_stats(ZBX_DC_HOST *host, unsigned char type, in
 	}
 }
 
-static void	DCsync_items(zbx_dbsync_t *sync, int flags)
+static void	DCincrease_disable_until(const ZBX_DC_ITEM *item, int now)
+{
+	if (NULL == item->ifstatus)
+		return;
+
+	if (0 != item->ifstatus->agent.errors_from)
+	{
+		item->ifstatus->agent.disable_until = now + CONFIG_TIMEOUT;
+		zbx_hashset_insert(&config->hosts_availability, &item->hostid, sizeof(item->hostid));
+	}
+}
+
+/******************************************************************************
+ *                                                                            *
+ * Function: ifstatus_compare_func                                            *
+ *                                                                            *
+ * Purpose: comparison function for zbx_dc_ifstatus_t pointer vector          *
+ *                                                                            *
+ ******************************************************************************/
+static int	ifstatus_compare_func(const void *d1, const void *d2)
+{
+	const zbx_dc_ifstatus_t	*if1 = *(const zbx_dc_ifstatus_t **)d1;
+	const zbx_dc_ifstatus_t	*if2 = *(const zbx_dc_ifstatus_t **)d2;
+
+	ZBX_RETURN_IF_NOT_EQUAL(if1->interfaceid, if2->interfaceid);
+	ZBX_RETURN_IF_NOT_EQUAL(if1->agent_hash, if2->agent_hash);
+	return 0;
+}
+
+/******************************************************************************
+ *                                                                            *
+ * Function: dc_host_ifstatus_add                                             *
+ *                                                                            *
+ * Purpose: adds interface status to host interface status vector             *
+ *                                                                            *
+ * Parameters: hostid      - [IN] the host identifier                         *
+ *             interfaceid - [IN] the interface identifier                    *
+ *             agent_type  - [IN] the interface type                          *
+ *             agent_hash  - [IN] the hash sum of custom agent parameters     *
+ *             available   - [IN] the initial availability for new statuses   *
+ *                                                                            *
+ * Return value: The created or updated interface status object.              *
+ *                                                                            *
+ ******************************************************************************/
+static zbx_dc_ifstatus_t	*dc_host_ifstatus_add(zbx_uint64_t hostid, zbx_uint64_t interfaceid,
+		unsigned char agent_type, zbx_hash_t agent_hash, unsigned char available)
+{
+	zbx_dc_host_ifstatus_t	*hostif;
+	zbx_dc_ifstatus_t	*ifstatus;
+	int			index;
+
+	if (NULL == (hostif = (zbx_dc_host_ifstatus_t *)zbx_hashset_search(&config->hosts_ifstatus, &hostid)))
+	{
+		zbx_dc_host_ifstatus_t	hostif_local;
+
+		hostif_local.hostid = hostid;
+		hostif = zbx_hashset_insert(&config->hosts_ifstatus, &hostif_local, sizeof(hostif_local));
+		zbx_vector_ptr_create_ext(&hostif->ifs, __config_mem_malloc_func, __config_mem_realloc_func,
+				__config_mem_free_func);
+		index = FAIL;
+	}
+	else
+	{
+		zbx_dc_ifstatus_t	ifstatus_local;
+
+		ifstatus_local.interfaceid = interfaceid;
+		ifstatus_local.agent_hash = agent_hash;
+
+		index = zbx_vector_ptr_search(&hostif->ifs, &ifstatus_local, ifstatus_compare_func);
+	}
+
+	if (FAIL == index)
+	{
+		ifstatus = (zbx_dc_ifstatus_t *)__config_mem_malloc_func(NULL, sizeof(zbx_dc_ifstatus_t));
+		ifstatus->interfaceid = interfaceid;
+		ifstatus->agent_hash = agent_hash;
+		ifstatus->refcount = 1;
+		ifstatus->agent.available = available;
+		ifstatus->agent.disable_until = 0;
+		ifstatus->agent.errors_from = 0;
+		ifstatus->agent.error = (char *)zbx_strpool_intern("");
+		ifstatus->type = agent_type;
+		zbx_vector_ptr_append(&hostif->ifs, ifstatus);
+
+		zbx_hashset_insert(&config->hosts_availability, &hostid, sizeof(hostid));
+
+		return ifstatus;
+
+	}
+
+	ifstatus = hostif->ifs.values[index];
+	ifstatus->refcount++;
+
+	return ifstatus;
+}
+
+/******************************************************************************
+ *                                                                            *
+ * Function: dc_host_ifstatus_release                                         *
+ *                                                                            *
+ * Purpose: releases interface status, freeing resources as necessary         *
+ *                                                                            *
+ * Parameters: hostid   - [IN] the host identifier                            *
+ *             ifstatus - [IN] the interface status object                    *
+ *                                                                            *
+ ******************************************************************************/
+static void	dc_host_ifstatus_release(zbx_uint64_t hostid, zbx_dc_ifstatus_t *ifstatus)
+{
+	zbx_dc_host_ifstatus_t	*hostif;
+
+	if (0 != --ifstatus->refcount)
+		return;
+	if (NULL != (hostif = (zbx_dc_host_ifstatus_t *)zbx_hashset_search(&config->hosts_ifstatus, &hostid)))
+	{
+		int	index;
+
+		if (FAIL != (index = zbx_vector_ptr_search(&hostif->ifs, ifstatus, ZBX_DEFAULT_PTR_COMPARE_FUNC)))
+		{
+			zbx_vector_ptr_remove_noorder(&hostif->ifs, index);
+			if (0 == hostif->ifs.values_num)
+			{
+				zbx_vector_ptr_destroy(&hostif->ifs);
+				zbx_hashset_remove_direct(&config->hosts_ifstatus, hostif);
+			}
+
+			zbx_hashset_insert(&config->hosts_availability, &hostid, sizeof(hostid));
+		}
+	}
+
+	zbx_strpool_release(ifstatus->agent.error);
+	__config_mem_free_func(ifstatus);
+}
+
+static void	DCsync_items(zbx_dbsync_t *sync, int flags, unsigned char mode)
 {
 	const char		*__function_name = "DCsync_items";
 
@@ -2287,10 +2347,11 @@ static void	DCsync_items(zbx_dbsync_t *sync, int flags)
 	ZBX_DC_ITEM_HK		*item_hk, item_hk_local;
 
 	time_t			now;
-	unsigned char		status, type, value_type, old_poller_type;
+	unsigned char		status, type, value_type, old_poller_type, agent_type;
 	int			found, update_index, ret, i,  old_nextcheck;
-	zbx_uint64_t		itemid, hostid;
+	zbx_uint64_t		itemid, hostid, old_interfaceid, agent_interfaceid;
 	zbx_vector_ptr_t	dep_items;
+	zbx_hash_t		agent_hash, old_agent_hash;
 
 	zbx_vector_ptr_create(&dep_items);
 
@@ -2300,6 +2361,9 @@ static void	DCsync_items(zbx_dbsync_t *sync, int flags)
 
 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
 	{
+		agent_hash = 0;
+		agent_type = ZBX_AGENT_UNKNOWN;
+
 		/* removed rows will be always added at the end */
 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
 			break;
@@ -2353,7 +2417,6 @@ static void	DCsync_items(zbx_dbsync_t *sync, int flags)
 		item->hostid = hostid;
 		DCstrpool_replace(found, &item->port, row[8]);
 		item->flags = (unsigned char)atoi(row[24]);
-		ZBX_DBROW2UINT64(item->interfaceid, row[25]);
 
 		if (ZBX_HK_OPTION_ENABLED == config->config->hk.history_global)
 		{
@@ -2392,9 +2455,13 @@ static void	DCsync_items(zbx_dbsync_t *sync, int flags)
 			item->poller_type = ZBX_NO_POLLER;
 			item->queue_priority = ZBX_QUEUE_PRIORITY_NORMAL;
 			item->schedulable = 1;
+			item->ifstatus = NULL;
+			old_interfaceid = 0;
 		}
 		else
 		{
+			old_interfaceid = item->interfaceid;
+
 			if (item->type != type)
 				flags |= ZBX_ITEM_TYPE_CHANGED;
 
@@ -2405,6 +2472,9 @@ static void	DCsync_items(zbx_dbsync_t *sync, int flags)
 				dc_host_update_agent_stats(host, item->type, -1);
 		}
 
+		ZBX_DBROW2UINT64(item->interfaceid, row[25]);
+
+
 		if (ITEM_STATUS_ACTIVE == status)
 			dc_host_update_agent_stats(host, type, 1);
 
@@ -2473,6 +2543,10 @@ static void	DCsync_items(zbx_dbsync_t *sync, int flags)
 				else
 					snmpitem->snmp_oid_type = ZBX_SNMP_OID_TYPE_NORMAL;
 			}
+
+			agent_hash = ZBX_DEFAULT_STRING_HASH_FUNC(snmpitem->snmpv3_contextname);
+			agent_hash = ZBX_DEFAULT_STRING_HASH_ALGO(item->port, strlen(item->port), agent_hash);
+			agent_type = ZBX_AGENT_SNMP;
 		}
 		else if (NULL != (snmpitem = (ZBX_DC_SNMPITEM *)zbx_hashset_search(&config->snmpitems, &itemid)))
 		{
@@ -2495,6 +2569,9 @@ static void	DCsync_items(zbx_dbsync_t *sync, int flags)
 			ipmiitem = (ZBX_DC_IPMIITEM *)DCfind_id(&config->ipmiitems, itemid, sizeof(ZBX_DC_IPMIITEM), &found);
 
 			DCstrpool_replace(found, &ipmiitem->ipmi_sensor, row[13]);
+
+			agent_hash = 0;
+			agent_type = ZBX_AGENT_IPMI;
 		}
 		else if (NULL != (ipmiitem = (ZBX_DC_IPMIITEM *)zbx_hashset_search(&config->ipmiitems, &itemid)))
 		{
@@ -2649,6 +2726,10 @@ static void	DCsync_items(zbx_dbsync_t *sync, int flags)
 			DCstrpool_replace(found, &jmxitem->username, row[20]);
 			DCstrpool_replace(found, &jmxitem->password, row[21]);
 			DCstrpool_replace(found, &jmxitem->jmx_endpoint, row[37]);
+
+			agent_hash = ZBX_DEFAULT_STRING_HASH_FUNC(jmxitem->jmx_endpoint);
+
+			agent_type = ZBX_AGENT_JMX;
 		}
 		else if (NULL != (jmxitem = (ZBX_DC_JMXITEM *)zbx_hashset_search(&config->jmxitems, &itemid)))
 		{
@@ -2745,6 +2826,13 @@ static void	DCsync_items(zbx_dbsync_t *sync, int flags)
 			zbx_hashset_remove_direct(&config->httpitems, httpitem);
 		}
 
+		/* Zabbix agent (passive) items */
+		if (ITEM_TYPE_ZABBIX == item->type)
+		{
+			agent_hash = 0;
+			agent_type = ZBX_AGENT_ZABBIX;
+		}
+
 		/* it is crucial to update type specific (config->snmpitems, config->ipmiitems, etc.) hashsets before */
 		/* attempting to requeue an item because type specific properties are used to arrange items in queues */
 
@@ -2766,6 +2854,41 @@ static void	DCsync_items(zbx_dbsync_t *sync, int flags)
 		}
 
 		DCupdate_item_queue(item, old_poller_type, old_nextcheck);
+
+		/* update interface status references */
+
+		old_agent_hash = (NULL == item->ifstatus ? 0 : item->ifstatus->agent_hash);
+
+		/* disable agent status tracking for not monitored items */
+		if (ITEM_STATUS_ACTIVE != item->status || HOST_STATUS_MONITORED != host->status)
+			agent_type = ZBX_AGENT_UNKNOWN;
+
+		if (0 != host->proxy_hostid)
+		{
+			/* set virtual agent interface for items monitored by proxy - maximum */
+			/* one interface per interface type (zabbix, snmp, ipmi, jxmx)        */
+			agent_interfaceid = 0;
+			agent_hash = ZBX_DEFAULT_STRING_HASH_ALGO(&agent_type, 1, 0);
+		}
+		else
+			agent_interfaceid = item->interfaceid;
+
+		if (old_agent_hash != agent_hash || agent_interfaceid != old_interfaceid)
+		{
+			if (NULL != item->ifstatus)
+				dc_host_ifstatus_release(item->hostid, item->ifstatus);
+
+			if (ZBX_AGENT_UNKNOWN != agent_type)
+			{
+				unsigned char	available;
+
+				available = (ZBX_DBSYNC_INIT == mode ? HOST_AVAILABLE_UNSET : HOST_AVAILABLE_UNKNOWN);
+				item->ifstatus = dc_host_ifstatus_add(item->hostid, agent_interfaceid, agent_type,
+						agent_hash, available);
+			}
+			else
+				item->ifstatus = NULL;
+		}
 	}
 
 	/* update dependent item vectors within master items */
@@ -2969,6 +3092,9 @@ static void	DCsync_items(zbx_dbsync_t *sync, int flags)
 			zbx_hashset_remove_direct(&config->httpitems, httpitem);
 		}
 
+		if (NULL != item->ifstatus)
+			dc_host_ifstatus_release(item->hostid, item->ifstatus);
+
 		/* items */
 
 		item_hk_local.hostid = item->hostid;
@@ -4669,7 +4795,7 @@ void	DCsync_configuration(unsigned char mode)
 
 	sec = zbx_time();
 	/* relies on hosts, proxies and interfaces, must be after DCsync_{hosts,interfaces}() */
-	DCsync_items(&items_sync, flags);
+	DCsync_items(&items_sync, flags, mode);
 	isec2 = zbx_time() - sec;
 
 	sec = zbx_time();
@@ -5434,6 +5560,8 @@ int	init_configuration_cache(char **error)
 			__config_mem_free_func);
 
 	CREATE_HASHSET(config->preprocops, 0);
+	CREATE_HASHSET(config->hosts_ifstatus, 0);
+	CREATE_HASHSET(config->hosts_availability, 0);
 
 	CREATE_HASHSET_EXT(config->items_hk, 100, __config_item_hk_hash, __config_item_hk_compare);
 	CREATE_HASHSET_EXT(config->hosts_h, 10, __config_host_h_hash, __config_host_h_compare);
@@ -5505,7 +5633,6 @@ int	init_configuration_cache(char **error)
 	config->status = (ZBX_DC_STATUS *)__config_mem_malloc_func(NULL, sizeof(ZBX_DC_STATUS));
 	config->status->last_update = 0;
 
-	config->availability_diff_ts = 0;
 	config->sync_ts = 0;
 	config->item_sync_ts = 0;
 	config->proxy_lastaccess_ts = time(NULL);
@@ -5586,23 +5713,7 @@ static void	DCget_host(DC_HOST *dst_host, const ZBX_DC_HOST *src_host)
 	dst_host->maintenance_status = src_host->maintenance_status;
 	dst_host->maintenance_type = src_host->maintenance_type;
 	dst_host->maintenance_from = src_host->maintenance_from;
-	dst_host->errors_from = src_host->errors_from;
-	dst_host->available = src_host->available;
-	dst_host->disable_until = src_host->disable_until;
-	dst_host->snmp_errors_from = src_host->snmp_errors_from;
-	dst_host->snmp_available = src_host->snmp_available;
-	dst_host->snmp_disable_until = src_host->snmp_disable_until;
-	dst_host->ipmi_errors_from = src_host->ipmi_errors_from;
-	dst_host->ipmi_available = src_host->ipmi_available;
-	dst_host->ipmi_disable_until = src_host->ipmi_disable_until;
-	dst_host->jmx_errors_from = src_host->jmx_errors_from;
-	dst_host->jmx_available = src_host->jmx_available;
-	dst_host->jmx_disable_until = src_host->jmx_disable_until;
 	dst_host->status = src_host->status;
-	strscpy(dst_host->error, src_host->error);
-	strscpy(dst_host->snmp_error, src_host->snmp_error);
-	strscpy(dst_host->ipmi_error, src_host->ipmi_error);
-	strscpy(dst_host->jmx_error, src_host->jmx_error);
 	dst_host->tls_connect = src_host->tls_connect;
 	dst_host->tls_accept = src_host->tls_accept;
 #if defined(HAVE_POLARSSL) || defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
@@ -5903,6 +6014,16 @@ static void	DCget_item(DC_ITEM *dst_item, const ZBX_DC_ITEM *src_item)
 
 	dst_item->error = zbx_strdup(NULL, src_item->error);
 
+	if (NULL != src_item->ifstatus)
+	{
+		dst_item->agent.available = src_item->ifstatus->agent.available;
+		dst_item->agent.errors_from = src_item->ifstatus->agent.errors_from;
+		dst_item->agent.disable_until = src_item->ifstatus->agent.disable_until;
+		dst_item->agent.error = zbx_strdup(NULL, src_item->ifstatus->agent.error);
+	}
+	else
+		dst_item->agent.error = zbx_strdup(NULL, "");
+
 	switch (src_item->value_type)
 	{
 		case ITEM_VALUE_TYPE_FLOAT:
@@ -6163,6 +6284,7 @@ void	DCconfig_clean_items(DC_ITEM *items, int *errcodes, size_t num)
 
 		zbx_free(items[i].delay);
 		zbx_free(items[i].error);
+		zbx_free(items[i].agent.error);
 	}
 }
 
@@ -7374,7 +7496,9 @@ int	DCconfig_get_poller_items(unsigned char poller_type, DC_ITEM *items)
 		/* don't apply unreachable item/host throttling for prioritized items */
 		if (ZBX_QUEUE_PRIORITY_HIGH != dc_item->queue_priority)
 		{
-			if (0 == (disable_until = DCget_disable_until(dc_item, dc_host)))
+			disable_until = (NULL != dc_item->ifstatus ? dc_item->ifstatus->agent.disable_until : 0);
+
+			if (0 == disable_until)
 			{
 				/* move reachable items on reachable hosts to normal pollers */
 				if (ZBX_POLLER_TYPE_UNREACHABLE == poller_type &&
@@ -7397,7 +7521,7 @@ int	DCconfig_get_poller_items(unsigned char poller_type, DC_ITEM *items)
 					continue;
 				}
 
-				DCincrease_disable_until(dc_item, dc_host, now);
+				DCincrease_disable_until(dc_item, now);
 			}
 		}
 
@@ -7491,7 +7615,9 @@ int	DCconfig_get_ipmi_poller_items(int now, DC_ITEM *items, int items_num, int *
 		/* don't apply unreachable item/host throttling for prioritized items */
 		if (ZBX_QUEUE_PRIORITY_HIGH != dc_item->queue_priority)
 		{
-			if (0 != (disable_until = DCget_disable_until(dc_item, dc_host)))
+			disable_until = (NULL != dc_item->ifstatus ? dc_item->ifstatus->agent.disable_until : 0);
+
+			if (0 != disable_until)
 			{
 				if (disable_until > now)
 				{
@@ -7500,7 +7626,7 @@ int	DCconfig_get_ipmi_poller_items(int now, DC_ITEM *items, int items_num, int *
 					continue;
 				}
 
-				DCincrease_disable_until(dc_item, dc_host, now);
+				DCincrease_disable_until(dc_item, now);
 			}
 		}
 
@@ -7756,275 +7882,55 @@ void	zbx_dc_requeue_unreachable_items(zbx_uint64_t *itemids, size_t itemids_num)
 
 /******************************************************************************
  *                                                                            *
- * Function: DChost_get_agent_availability                                    *
+ * Function: dc_set_agent_status                                              *
  *                                                                            *
- * Purpose: get host availability data for the specified agent                *
+ * Purpose: updates agent status belonging to the specified host              *
  *                                                                            *
- * Parameters: dc_host      - [IN] the host                                   *
- *             agent        - [IN] the agent (see ZBX_FLAGS_AGENT_STATUS_*    *
- *                                 defines                                    *
- *             availability - [OUT] the host availability data                *
+ * Parameters: hostid        - [IN] the owner host identifier                 *
+ *             agent         - [OUT] the agent status to update               *
+ *             available     - [IN] the agent availability                    *
+ *             disable_until - [IN] the time until the checks are disabled    *
+ *             errors_from   - [IN] the time since errors started             *
+ *             error         - [IN] the error message                         *
  *                                                                            *
- * Comments: The configuration cache must be locked already.                  *
+ * Return value: flags of changed values, see ZBX_AGENT_STATUS_ defines       *
  *                                                                            *
  ******************************************************************************/
-static void	DChost_get_agent_availability(const ZBX_DC_HOST *dc_host, unsigned char agent_type,
-		zbx_agent_availability_t *agent)
+static unsigned int	dc_set_agent_status(zbx_uint64_t hostid, zbx_agent_status_t *dst, unsigned char available,
+		int disable_until, int errors_from, const char *error)
 {
+	unsigned int	flags = ZBX_AGENT_STATUS_NONE;
 
-	agent->flags = ZBX_FLAGS_AGENT_STATUS;
-
-	switch (agent_type)
+	if (dst->available != available)
 	{
-		case ZBX_AGENT_ZABBIX:
-			agent->available = dc_host->available;
-			agent->error = zbx_strdup(agent->error, dc_host->error);
-			agent->errors_from = dc_host->errors_from;
-			agent->disable_until = dc_host->disable_until;
-			break;
-		case ZBX_AGENT_SNMP:
-			agent->available = dc_host->snmp_available;
-			agent->error = zbx_strdup(agent->error, dc_host->snmp_error);
-			agent->errors_from = dc_host->snmp_errors_from;
-			agent->disable_until = dc_host->snmp_disable_until;
-			break;
-		case ZBX_AGENT_IPMI:
-			agent->available = dc_host->ipmi_available;
-			agent->error = zbx_strdup(agent->error, dc_host->ipmi_error);
-			agent->errors_from = dc_host->ipmi_errors_from;
-			agent->disable_until = dc_host->ipmi_disable_until;
-			break;
-		case ZBX_AGENT_JMX:
-			agent->available = dc_host->jmx_available;
-			agent->error = zbx_strdup(agent->error, dc_host->jmx_error);
-			agent->errors_from = dc_host->jmx_errors_from;
-			agent->disable_until = dc_host->jmx_disable_until;
-			break;
-	}
-}
-
-static void	DCagent_set_availability(zbx_agent_availability_t *av,  unsigned char *available, const char **error,
-		int *errors_from, int *disable_until)
-{
-#define AGENT_AVAILABILITY_ASSIGN(flags, mask, dst, src)	\
-	if (0 != (flags & mask))				\
-	{							\
-		if (dst != src)					\
-			dst = src;				\
-		else						\
-			flags &= (~(mask));			\
+		dst->available = available;
+		flags |= ZBX_AGENT_STATUS_AVAILABLE;
 	}
 
-#define AGENT_AVAILABILITY_ASSIGN_STR(flags, mask, dst, src)	\
-	if (0 != (flags & mask))				\
-	{							\
-		if (0 != strcmp(dst, src))			\
-			DCstrpool_replace(1, &dst, src);	\
-		else						\
-			flags &= (~(mask));			\
+	if (dst->errors_from != errors_from)
+	{
+		dst->errors_from = errors_from;
+		flags |= ZBX_AGENT_STATUS_ERRORS_FROM;
 	}
 
-	AGENT_AVAILABILITY_ASSIGN(av->flags, ZBX_FLAGS_AGENT_STATUS_AVAILABLE, *available, av->available);
-	AGENT_AVAILABILITY_ASSIGN_STR(av->flags, ZBX_FLAGS_AGENT_STATUS_ERROR, *error, av->error);
-	AGENT_AVAILABILITY_ASSIGN(av->flags, ZBX_FLAGS_AGENT_STATUS_ERRORS_FROM, *errors_from, av->errors_from);
-	AGENT_AVAILABILITY_ASSIGN(av->flags, ZBX_FLAGS_AGENT_STATUS_DISABLE_UNTIL, *disable_until, av->disable_until);
-
-#undef AGENT_AVAILABILITY_ASSIGN_STR
-#undef AGENT_AVAILABILITY_ASSIGN
-}
-
-/******************************************************************************
- *                                                                            *
- * Function: DChost_set_agent_availability                                    *
- *                                                                            *
- * Purpose: set host availability data in configuration cache                 *
- *                                                                            *
- * Parameters: dc_host      - [OUT] the host                                  *
- *             availability - [IN/OUT] the host availability data             *
- *                                                                            *
- * Return value: SUCCEED - at least one availability field was updated        *
- *               FAIL    - no availability fields were updated                *
- *                                                                            *
- * Comments: The configuration cache must be locked already.                  *
- *                                                                            *
- *           This function clears availability flags of non updated fields    *
- *           updated leaving only flags identifying changed fields.           *
- *                                                                            *
- ******************************************************************************/
-static int	DChost_set_agent_availability(ZBX_DC_HOST *dc_host, int now, unsigned char agent_type,
-		zbx_agent_availability_t *agent)
-{
-	switch (agent_type)
+	if (dst->disable_until != disable_until)
 	{
-		case ZBX_AGENT_ZABBIX:
-			DCagent_set_availability(agent, &dc_host->available,
-					&dc_host->error, &dc_host->errors_from, &dc_host->disable_until);
-			break;
-		case ZBX_AGENT_SNMP:
-			DCagent_set_availability(agent, &dc_host->snmp_available,
-					&dc_host->snmp_error, &dc_host->snmp_errors_from, &dc_host->snmp_disable_until);
-			break;
-		case ZBX_AGENT_IPMI:
-			DCagent_set_availability(agent, &dc_host->ipmi_available,
-					&dc_host->ipmi_error, &dc_host->ipmi_errors_from, &dc_host->ipmi_disable_until);
-			break;
-		case ZBX_AGENT_JMX:
-			DCagent_set_availability(agent, &dc_host->jmx_available,
-					&dc_host->jmx_error, &dc_host->jmx_errors_from, &dc_host->jmx_disable_until);
-			break;
+		dst->disable_until = disable_until;
+		flags |= ZBX_AGENT_STATUS_DISABLE_UNTIL;
 	}
 
-	if (ZBX_FLAGS_AGENT_STATUS_NONE == agent->flags)
-		return FAIL;
-
-	if (0 != (agent->flags & (ZBX_FLAGS_AGENT_STATUS_AVAILABLE | ZBX_FLAGS_AGENT_STATUS_ERROR)))
-		dc_host->availability_ts = now;
-
-	return SUCCEED;
-}
-
-/******************************************************************************
- *                                                                            *
- * Function: DChost_set_availability                                          *
- *                                                                            *
- * Purpose: set host availability data in configuration cache                 *
- *                                                                            *
- * Parameters: dc_host      - [OUT] the host                                  *
- *             availability - [IN/OUT] the host availability data             *
- *                                                                            *
- * Return value: SUCCEED - at least one availability field was updated        *
- *               FAIL    - no availability fields were updated                *
- *                                                                            *
- * Comments: The configuration cache must be locked already.                  *
- *                                                                            *
- *           This function clears availability flags of non updated fields    *
- *           updated leaving only flags identifying changed fields.           *
- *                                                                            *
- ******************************************************************************/
-static int	DChost_set_availability(ZBX_DC_HOST *dc_host, int now, zbx_host_availability_t *ha)
-{
-	int		i;
-	unsigned char	flags = ZBX_FLAGS_AGENT_STATUS_NONE;
-
-	DCagent_set_availability(&ha->agents[ZBX_AGENT_ZABBIX], &dc_host->available, &dc_host->error,
-			&dc_host->errors_from, &dc_host->disable_until);
-	DCagent_set_availability(&ha->agents[ZBX_AGENT_SNMP], &dc_host->snmp_available, &dc_host->snmp_error,
-			&dc_host->snmp_errors_from, &dc_host->snmp_disable_until);
-	DCagent_set_availability(&ha->agents[ZBX_AGENT_IPMI], &dc_host->ipmi_available, &dc_host->ipmi_error,
-			&dc_host->ipmi_errors_from, &dc_host->ipmi_disable_until);
-	DCagent_set_availability(&ha->agents[ZBX_AGENT_JMX], &dc_host->jmx_available, &dc_host->jmx_error,
-			&dc_host->jmx_errors_from, &dc_host->jmx_disable_until);
-
-	for (i = 0; i < ZBX_AGENT_MAX; i++)
-		flags |= ha->agents[i].flags;
-
-	if (ZBX_FLAGS_AGENT_STATUS_NONE == flags)
-		return FAIL;
-
-	if (0 != (flags & (ZBX_FLAGS_AGENT_STATUS_AVAILABLE | ZBX_FLAGS_AGENT_STATUS_ERROR)))
-		dc_host->availability_ts = now;
-
-	return SUCCEED;
-}
-
-/******************************************************************************
- *                                                                            *
- * Function: zbx_host_availability_init                                       *
- *                                                                            *
- * Purpose: initializes host availability data                                *
- *                                                                            *
- * Parameters: availability - [IN/OUT] host availability data                 *
- *                                                                            *
- ******************************************************************************/
-void	zbx_host_availability_init(zbx_host_availability_t *availability, zbx_uint64_t hostid)
-{
-	memset(availability, 0, sizeof(zbx_host_availability_t));
-	availability->hostid = hostid;
-}
-
-/******************************************************************************
- *                                                                            *
- * Function: zbx_host_availability_clean                                      *
- *                                                                            *
- * Purpose: releases resources allocated to store host availability data      *
- *                                                                            *
- * Parameters: availability - [IN] host availability data                     *
- *                                                                            *
- ******************************************************************************/
-void	zbx_host_availability_clean(zbx_host_availability_t *ha)
-{
-	int	i;
-
-	for (i = 0; i < ZBX_AGENT_MAX; i++)
-		zbx_free(ha->agents[i].error);
-}
-
-/******************************************************************************
- *                                                                            *
- * Function: zbx_host_availability_free                                       *
- *                                                                            *
- * Purpose: frees host availability data                                      *
- *                                                                            *
- * Parameters: availability - [IN] host availability data                     *
- *                                                                            *
- ******************************************************************************/
-void	zbx_host_availability_free(zbx_host_availability_t *availability)
-{
-	zbx_host_availability_clean(availability);
-	zbx_free(availability);
-}
-
-/******************************************************************************
- *                                                                            *
- * Function: zbx_agent_availability_init                                      *
- *                                                                            *
- * Purpose: initializes agent availability with the specified data            *
- *                                                                            *
- * Parameters: availability  - [IN/OUT] agent availability data               *
- *             hostid        - [IN] the host identifier                       *
- *             flags         - [IN] the availability flags indicating which   *
- *                                  availability fields to set                *
- *             available     - [IN] the availability data                     *
- *             error         - [IN]                                           *
- *             errors_from   - [IN]                                           *
- *             disable_until - [IN]                                           *
- *                                                                            *
- ******************************************************************************/
-static void	zbx_agent_availability_init(zbx_agent_availability_t *agent, unsigned char available, const char *error,
-		int errors_from, int disable_until)
-{
-	agent->flags = ZBX_FLAGS_AGENT_STATUS;
-	agent->available = available;
-	agent->error = zbx_strdup(agent->error, error);
-	agent->errors_from = errors_from;
-	agent->disable_until = disable_until;
-}
-
-/******************************************************************************
- *                                                                            *
- * Function: zbx_host_availability_is_set                                     *
- *                                                                            *
- * Purpose: checks host availability if any agent availability field is set   *
- *                                                                            *
- * Parameters: availability - [IN] host availability data                     *
- *                                                                            *
- * Return value: SUCCEED - an agent availability field is set                 *
- *               FAIL - no agent availability fields are set                  *
- *                                                                            *
- ******************************************************************************/
-int	zbx_host_availability_is_set(const zbx_host_availability_t *ha)
-{
-	int	i;
-
-	for (i = 0; i < ZBX_AGENT_MAX; i++)
+	if (0 != strcmp(dst->error, error))
 	{
-		if (ZBX_FLAGS_AGENT_STATUS_NONE != ha->agents[i].flags)
-			return SUCCEED;
+		zbx_strpool_release(dst->error);
+		dst->error = (char *)zbx_strpool_intern(error);
+		flags |= ZBX_AGENT_STATUS_ERROR;
 	}
 
-	return FAIL;
-}
+	if (ZBX_AGENT_STATUS_NONE != flags)
+		zbx_hashset_insert(&config->hosts_availability, &hostid, sizeof(hostid));
 
+	return flags;
+}
 /**************************************************************************************
  *                                                                                    *
  * Host availability update example                                                   *
@@ -8066,39 +7972,31 @@ int	zbx_host_availability_is_set(const zbx_host_availability_t *ha)
 
 /******************************************************************************
  *                                                                            *
- * Function: DChost_activate                                                  *
+ * Function: zbx_dc_item_activate                                             *
  *                                                                            *
- * Purpose: set host as available based on the agent availability data        *
+ * Purpose: updates item's agent availability to available                    *
  *                                                                            *
- * Parameters: hostid     - [IN] the host identifier                          *
- *             agent_type - [IN] the agent type (see ZBX_AGENT_* defines)     *
- *             ts         - [IN] the last timestamp                           *
- *             in         - [IN/OUT] IN: the caller's agent availability data *
- *                                  OUT: the agent availability data in cache *
- *                                       before changes                       *
- *             out        - [OUT] the agent availability data after changes   *
+ * Parameters: item - [IN] the item                                           *
  *                                                                            *
- * Return value: SUCCEED - the host was activated successfully                *
- *               FAIL    - the host was already activated or activation       *
- *                         failed                                             *
+ * Return value: flags of changed values, see ZBX_AGENT_STATUS_ defines       *
  *                                                                            *
  * Comments: The host availability fields are updated according to the above  *
  *           schema.                                                          *
  *                                                                            *
  ******************************************************************************/
-int	DChost_activate(zbx_uint64_t hostid, unsigned char agent_type, const zbx_timespec_t *ts,
-		zbx_agent_availability_t *in, zbx_agent_availability_t *out)
+unsigned int	zbx_dc_item_activate(const DC_ITEM *item)
 {
-	int		ret = FAIL;
+	unsigned int	flags = ZBX_AGENT_STATUS_NONE;
 	ZBX_DC_HOST	*dc_host;
+	ZBX_DC_ITEM	*dc_item;
 
 	/* don't try activating host if there were no errors detected */
-	if (0 == in->errors_from && HOST_AVAILABLE_TRUE == in->available)
+	if (0 == item->agent.errors_from && HOST_AVAILABLE_TRUE == item->agent.available)
 		goto out;
 
 	LOCK_CACHE;
 
-	if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &hostid)))
+	if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &item->host.hostid)))
 		goto unlock;
 
 	/* Don't try activating host if:                  */
@@ -8110,57 +8008,53 @@ int	DChost_activate(zbx_uint64_t hostid, unsigned char agent_type, const zbx_tim
 		goto unlock;
 	}
 
-	DChost_get_agent_availability(dc_host, agent_type, in);
-	zbx_agent_availability_init(out, HOST_AVAILABLE_TRUE, "", 0, 0);
-	DChost_set_agent_availability(dc_host, ts->sec, agent_type, out);
+	if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &item->itemid)) ||
+			NULL == dc_item->ifstatus)
+	{
+		goto unlock;
+	}
 
-	if (ZBX_FLAGS_AGENT_STATUS_NONE != out->flags)
-		ret = SUCCEED;
+	flags = dc_set_agent_status(item->host.hostid, &dc_item->ifstatus->agent, HOST_AVAILABLE_TRUE, 0, 0, "");
 unlock:
 	UNLOCK_CACHE;
 out:
-	return ret;
+	return flags;
 }
 
 /******************************************************************************
  *                                                                            *
- * Function: DChost_deactivate                                                *
+ * Function: zbx_dc_item_deactivate                                           *
  *                                                                            *
- * Purpose: attempt to set host as unavailable based on agent availability    *
+ * Purpose: updates item's agent availability timeouts and sets agent as      *
+ *          unavailable if enough time has passed                             *
  *                                                                            *
- * Parameters: hostid     - [IN] the host identifier                          *
- *             agent_type - [IN] the agent type (see ZBX_AGENT_* defines)     *
- *             ts         - [IN] the last timestamp                           *
- *             in         - [IN/OUT] IN: the caller's host availability data  *
- *                                  OUT: the host availability data in cache  *
- *                                       before changes                       *
- *             out        - [OUT] the host availability data after changes    *
- *             error      - [IN] the error message                            *
- *                                                                            *
- * Return value: SUCCEED - the host was deactivated successfully              *
- *               FAIL    - the host was already deactivated or deactivation   *
- *                         failed                                             *
+ * Parameters: item      - [IN] the item                                      *
+ *             ts        - [IN] the error timestamp                           *
+ *             error_msg - [IN] the error message                             *
+ *                                                                            *
+ * Return value: flags of changed values, see ZBX_AGENT_STATUS_ defines       *
  *                                                                            *
  * Comments: The host availability fields are updated according to the above  *
  *           schema.                                                          *
  *                                                                            *
  ******************************************************************************/
-int	DChost_deactivate(zbx_uint64_t hostid, unsigned char agent_type, const zbx_timespec_t *ts,
-		zbx_agent_availability_t *in, zbx_agent_availability_t *out, const char *error_msg)
+unsigned int	zbx_dc_item_deactivate(const DC_ITEM *item, const zbx_timespec_t *ts, const char *error_msg)
 {
-	int		ret = FAIL, errors_from,disable_until;
+	unsigned int	flags = ZBX_AGENT_STATUS_NONE;
+	int		errors_from, disable_until;
 	const char	*error;
 	unsigned char	available;
 	ZBX_DC_HOST	*dc_host;
+	ZBX_DC_ITEM	*dc_item;
 
 
 	/* don't try deactivating host if the unreachable delay has not passed since the first error */
-	if (CONFIG_UNREACHABLE_DELAY > ts->sec - in->errors_from)
+	if (CONFIG_UNREACHABLE_DELAY > ts->sec - item->agent.errors_from)
 		goto out;
 
 	LOCK_CACHE;
 
-	if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &hostid)))
+	if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &item->host.hostid)))
 		goto unlock;
 
 	/* Don't try deactivating host if:                */
@@ -8172,12 +8066,16 @@ int	DChost_deactivate(zbx_uint64_t hostid, unsigned char agent_type, const zbx_t
 		goto unlock;
 	}
 
-	DChost_get_agent_availability(dc_host, agent_type, in);
+	if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &item->itemid)) ||
+			NULL == dc_item->ifstatus)
+	{
+		goto unlock;
+	}
 
-	available = in->available;
-	error = in->error;
+	available = (HOST_AVAILABLE_UNSET == item->agent.available ? HOST_AVAILABLE_UNKNOWN : item->agent.available);
+	error = item->agent.error;
 
-	if (0 == in->errors_from)
+	if (0 == item->agent.errors_from)
 	{
 		/* first error, schedule next unreachable check */
 		errors_from = ts->sec;
@@ -8185,8 +8083,8 @@ int	DChost_deactivate(zbx_uint64_t hostid, unsigned char agent_type, const zbx_t
 	}
 	else
 	{
-		errors_from = in->errors_from;
-		disable_until = in->disable_until;
+		errors_from = item->agent.errors_from;
+		disable_until = item->agent.disable_until;
 
 		/* Check if other pollers haven't already attempted deactivating host. */
 		/* In that case should wait the initial unreachable delay before       */
@@ -8209,63 +8107,12 @@ int	DChost_deactivate(zbx_uint64_t hostid, unsigned char agent_type, const zbx_t
 		}
 	}
 
-	zbx_agent_availability_init(out, available, error, errors_from, disable_until);
-	DChost_set_agent_availability(dc_host, ts->sec, agent_type, out);
-
-	if (ZBX_FLAGS_AGENT_STATUS_NONE != out->flags)
-		ret = SUCCEED;
+	flags = dc_set_agent_status(item->host.hostid, &dc_item->ifstatus->agent, available, disable_until, errors_from,
+			error);
 unlock:
 	UNLOCK_CACHE;
 out:
-	return ret;
-}
-
-/******************************************************************************
- *                                                                            *
- * Function: DCset_hosts_availability                                         *
- *                                                                            *
- * Purpose: update availability of hosts in configuration cache and return    *
- *          the updated field flags                                           *
- *                                                                            *
- * Parameters: availabilities - [IN/OUT] the hosts availability data          *
- *                                                                            *
- * Return value: SUCCEED - at least one host availability data was updated    *
- *               FAIL    - no hosts were updated                              *
- *                                                                            *
- ******************************************************************************/
-int	DCset_hosts_availability(zbx_vector_ptr_t *availabilities)
-{
-	int			i;
-	ZBX_DC_HOST		*dc_host;
-	zbx_host_availability_t	*ha;
-	int			ret = FAIL, now;
-
-	now = time(NULL);
-
-	LOCK_CACHE;
-
-	for (i = 0; i < availabilities->values_num; i++)
-	{
-		ha = (zbx_host_availability_t *)availabilities->values[i];
-
-		if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &ha->hostid)))
-		{
-			int	j;
-
-			/* reset availability flags so this host is ignored when saving availability diff to DB */
-			for (j = 0; j < ZBX_AGENT_MAX; j++)
-				ha->agents[j].flags = ZBX_FLAGS_AGENT_STATUS_NONE;
-
-			continue;
-		}
-
-		if (SUCCEED == DChost_set_availability(dc_host, now, ha))
-			ret = SUCCEED;
-	}
-
-	UNLOCK_CACHE;
-
-	return ret;
+	return flags;
 }
 
 /******************************************************************************
@@ -10046,29 +9893,21 @@ void	zbx_config_clean(zbx_config_t *cfg)
 
 /******************************************************************************
  *                                                                            *
- * Function: DCreset_hosts_availability                                       *
- *                                                                            *
- * Purpose: resets host availability for disabled hosts and hosts without     *
- *          enabled items for the corresponding interface                     *
- *                                                                            *
- * Parameters: hosts - [OUT] changed host availability data                   *
- *                                                                            *
- * Return value: SUCCEED - host availability was reset for at least one host  *
- *               FAIL    - no hosts required availability reset               *
+ * Function: zbx_dc_reset_proxy_hosts_availability                            *
  *                                                                            *
- * Comments: This function resets host availability in configuration cache.   *
- *           The caller must perform corresponding database updates based     *
- *           on returned host availability reset data. On server the function *
- *           skips hosts handled by proxies.                                  *
+ * Purpose: resets host availability for hosts monitored by proxies with last *
+ *          seen time exceeding maximum heartbeat frequency                   *
  *                                                                            *
  ******************************************************************************/
-int	DCreset_hosts_availability(zbx_vector_ptr_t *hosts)
+void	zbx_dc_reset_proxy_hosts_availability()
 {
 	const char		*__function_name = "DCreset_hosts_availability";
 	ZBX_DC_HOST		*host;
+	ZBX_DC_PROXY		*proxy;
 	zbx_hashset_iter_t	iter;
-	zbx_host_availability_t	*ha = NULL;
-	int			now;
+	zbx_dc_host_ifstatus_t	*host_ifstatus;
+	zbx_dc_ifstatus_t	*ifstatus;
+	int			now, i;
 
 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
 
@@ -10080,163 +9919,56 @@ int	DCreset_hosts_availability(zbx_vector_ptr_t *hosts)
 
 	while (NULL != (host = (ZBX_DC_HOST *)zbx_hashset_iter_next(&iter)))
 	{
-		int	items_num = 0, snmp_items_num = 0, ipmi_items_num = 0, jmx_items_num = 0;
-
-		/* On server skip hosts handled by proxies. They are handled directly */
-		/* when receiving hosts' availability data from proxies.              */
-		/* Unless a host was just (re)assigned to a proxy or the proxy has    */
-		/* not updated its status during the maximum proxy heartbeat period.  */
-		/* In this case reset all interfaces to unknown status.               */
-		if (0 == host->reset_availability &&
-				0 != (program_type & ZBX_PROGRAM_TYPE_SERVER) && 0 != host->proxy_hostid)
-		{
-			ZBX_DC_PROXY	*proxy;
-
-			if (NULL != (proxy = (ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &host->proxy_hostid)))
-			{
-				/* SEC_PER_MIN is a tolerance interval, it was chosen arbitrarily */
-				if (ZBX_PROXY_HEARTBEAT_FREQUENCY_MAX + SEC_PER_MIN >= now - proxy->lastaccess)
-					continue;
-			}
-
-			host->reset_availability = 1;
-		}
-
-		if (NULL == ha)
-			ha = (zbx_host_availability_t *)zbx_malloc(NULL, sizeof(zbx_host_availability_t));
-
-		zbx_host_availability_init(ha, host->hostid);
+		if (0 == host->proxy_hostid)
+			continue;
 
-		if (0 == host->reset_availability)
+		if (NULL != (proxy = (ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &host->proxy_hostid)))
 		{
-			items_num = host->items_num;
-			snmp_items_num = host->snmp_items_num;
-			ipmi_items_num = host->ipmi_items_num;
-			jmx_items_num = host->jmx_items_num;
+			/* SEC_PER_MIN is a tolerance interval, it was chosen arbitrarily */
+			if (ZBX_PROXY_HEARTBEAT_FREQUENCY_MAX + SEC_PER_MIN >= now - proxy->lastaccess)
+				continue;
 		}
 
-		if (0 == items_num && HOST_AVAILABLE_UNKNOWN != host->available)
-			zbx_agent_availability_init(&ha->agents[ZBX_AGENT_ZABBIX], HOST_AVAILABLE_UNKNOWN, "", 0, 0);
-
-		if (0 == snmp_items_num && HOST_AVAILABLE_UNKNOWN != host->snmp_available)
-			zbx_agent_availability_init(&ha->agents[ZBX_AGENT_SNMP], HOST_AVAILABLE_UNKNOWN, "", 0, 0);
-
-		if (0 == ipmi_items_num && HOST_AVAILABLE_UNKNOWN != host->ipmi_available)
-			zbx_agent_availability_init(&ha->agents[ZBX_AGENT_IPMI], HOST_AVAILABLE_UNKNOWN, "", 0, 0);
-
-		if (0 == jmx_items_num && HOST_AVAILABLE_UNKNOWN != host->jmx_available)
-			zbx_agent_availability_init(&ha->agents[ZBX_AGENT_JMX], HOST_AVAILABLE_UNKNOWN, "", 0, 0);
+		if (NULL == (host_ifstatus = zbx_hashset_search(&config->hosts_ifstatus, &host->hostid)))
+			continue;
 
-		if (SUCCEED == zbx_host_availability_is_set(ha))
+		for (i = 0; i < host_ifstatus->ifs.values_num; i++)
 		{
-			if (SUCCEED == DChost_set_availability(host, now, ha))
-			{
-				zbx_vector_ptr_append(hosts, ha);
-				ha = NULL;
-			}
-			else
-				zbx_host_availability_clean(ha);
+			ifstatus = (zbx_dc_ifstatus_t *)host_ifstatus->ifs.values[i];
+			ifstatus->agent.available = HOST_AVAILABLE_UNKNOWN;
+			zbx_strpool_release(ifstatus->agent.error);
+			ifstatus->agent.error = (char *)zbx_strpool_intern("");
 		}
 
-		host->reset_availability = 0;
-	}
-	UNLOCK_CACHE;
-
-	zbx_free(ha);
-
-	zbx_vector_ptr_sort(hosts, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
-
-	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() hosts:%d", __function_name, hosts->values_num);
-
-	return 0 == hosts->values_num ? FAIL : SUCCEED;
-}
-
-/******************************************************************************
- *                                                                            *
- * Function: DCget_hosts_availability                                         *
- *                                                                            *
- * Purpose: gets availability data for hosts with availability data changed   *
- *          in period from last availability update to the specified          *
- *          timestamp                                                         *
- *                                                                            *
- * Parameters: hosts - [OUT] changed host availability data                   *
- *             ts    - [OUT] the availability diff timestamp                  *
- *                                                                            *
- * Return value: SUCCEED - availability was changed for at least one host     *
- *               FAIL    - no host availability was changed                   *
- *                                                                            *
- ******************************************************************************/
-int	DCget_hosts_availability(zbx_vector_ptr_t *hosts, int *ts)
-{
-	const char		*__function_name = "DCget_hosts_availability";
-	ZBX_DC_HOST		*host;
-	zbx_hashset_iter_t	iter;
-	zbx_host_availability_t	*ha = NULL;
-
-	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
-
-	LOCK_CACHE;
-
-	*ts = time(NULL);
-
-	zbx_hashset_iter_reset(&config->hosts, &iter);
-
-	while (NULL != (host = (ZBX_DC_HOST *)zbx_hashset_iter_next(&iter)))
-	{
-		if (config->availability_diff_ts <= host->availability_ts && host->availability_ts < *ts)
-		{
-			ha = (zbx_host_availability_t *)zbx_malloc(NULL, sizeof(zbx_host_availability_t));
-			zbx_host_availability_init(ha, host->hostid);
-
-			zbx_agent_availability_init(&ha->agents[ZBX_AGENT_ZABBIX], host->available, host->error,
-					host->errors_from, host->disable_until);
-			zbx_agent_availability_init(&ha->agents[ZBX_AGENT_SNMP], host->snmp_available, host->snmp_error,
-					host->snmp_errors_from, host->snmp_disable_until);
-			zbx_agent_availability_init(&ha->agents[ZBX_AGENT_IPMI], host->ipmi_available, host->ipmi_error,
-					host->ipmi_errors_from, host->ipmi_disable_until);
-			zbx_agent_availability_init(&ha->agents[ZBX_AGENT_JMX], host->jmx_available, host->jmx_error,
-					host->jmx_errors_from, host->jmx_disable_until);
-
-			zbx_vector_ptr_append(hosts, ha);
-		}
+		zbx_hashset_insert(&config->hosts_availability, &host->hostid, sizeof(host->hostid));
 	}
 
 	UNLOCK_CACHE;
 
-	zbx_vector_ptr_sort(hosts, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
-
-	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() hosts:%d", __function_name, hosts->values_num);
-
-	return 0 == hosts->values_num ? FAIL : SUCCEED;
+	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
 }
 
 /******************************************************************************
  *                                                                            *
- * Function: DCtouch_hosts_availability                                       *
+ * Function: zbx_dc_refresh_hosts_availability                                *
  *                                                                            *
- * Purpose: sets availability timestamp to current time for the specified     *
- *          hosts                                                             *
+ * Purpose: forces host availability to be refreshed                          *
  *                                                                            *
  * Parameters: hostids - [IN] the host identifiers                            *
  *                                                                            *
  ******************************************************************************/
-void	DCtouch_hosts_availability(const zbx_vector_uint64_t *hostids)
+void	zbx_dc_refresh_hosts_availability(const zbx_vector_uint64_t *hostids)
 {
-	const char	*__function_name = "DCtouch_hosts_availability";
-	ZBX_DC_HOST	*dc_host;
-	int		i, now;
+	const char	*__function_name = "zbx_dc_refresh_hosts_availability";
 
-	zabbix_log(LOG_LEVEL_DEBUG, "In %s() hostids:%d", __function_name, hostids->values_num);
+	int		i;
 
-	now = time(NULL);
+	zabbix_log(LOG_LEVEL_DEBUG, "In %s() hostids:%d", __function_name, hostids->values_num);
 
 	LOCK_CACHE;
 
 	for (i = 0; i < hostids->values_num; i++)
-	{
-		if (NULL != (dc_host = zbx_hashset_search(&config->hosts, &hostids->values[i])))
-			dc_host->availability_ts = now;
-	}
+		zbx_hashset_insert(&config->hosts_availability, &hostids->values[i], sizeof(hostids->values[i]));
 
 	UNLOCK_CACHE;
 
@@ -10478,24 +10210,6 @@ void	zbx_dc_get_actions_eval(zbx_vector_ptr_t *actions, zbx_hashset_t *uniq_cond
 
 /******************************************************************************
  *                                                                            *
- * Function: zbx_set_availability_update_ts                                   *
- *                                                                            *
- * Purpose: sets timestamp of the last availability update                    *
- *                                                                            *
- * Parameter: ts - [IN] the last availability update timestamp                *
- *                                                                            *
- * Comments: This function is used only by proxies when preparing host        *
- *           availability data to be sent to server.                          *
- *                                                                            *
- ******************************************************************************/
-void	zbx_set_availability_diff_ts(int ts)
-{
-	/* this data can't be accessed simultaneously from multiple processes - locking is not necessary */
-	config->availability_diff_ts = ts;
-}
-
-/******************************************************************************
- *                                                                            *
  * Function: corr_condition_clean                                             *
  *                                                                            *
  * Purpose: frees correlation condition                                       *
@@ -11404,3 +11118,352 @@ void	zbx_dc_get_proxy_lastaccess(zbx_vector_uint64_pair_t *lastaccess)
 		zbx_vector_uint64_pair_sort(lastaccess, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
 	}
 }
+
+/******************************************************************************
+ *                                                                            *
+ * Function: dc_get_aggregate_host_availability                               *
+ *                                                                            *
+ * Purpose: calculates aggregated availability by interface types for the     *
+ *          specified host                                                    *
+ *                                                                            *
+ * Parameter: hostid - [IN] the host identifier                               *
+ *            agents - [OUT] the availability status for all agent types      *
+ *                           (see ZBX_AGENT_  defines)                        *
+ *                                                                            *
+ * Comments: The status aggregation rules for an interface type are:          *
+ *              unknown   - no interfaces                                     *
+ *              unset     - only interfaces with unset status                 *
+ *              unknown   - interfaces with unset or unknown statuses         *
+ *              true      - at least one interface with true status and no    *
+ *                          interfaces with false status                      *
+ *              false     - at least one interface with false status and no   *
+ *                          interfaces with true status                       *
+ *              partial   - at least one interface with false status and one  *
+ *                          interface with true status                        *
+ *                                                                            *
+ ******************************************************************************/
+static void	dc_get_aggregate_host_availability(zbx_uint64_t hostid, zbx_agent_status_t *agents)
+{
+	zbx_dc_host_ifstatus_t	*host_ifstatus;
+	zbx_dc_ifstatus_t	*ifstatus;
+	zbx_agent_status_t	*agent;
+	int			i, available[ZBX_AGENT_MAX] = {-1, -1, -1, -1};
+
+	if (NULL == (host_ifstatus = zbx_hashset_search(&config->hosts_ifstatus, &hostid)))
+		return;
+
+	for (i = 0; i < host_ifstatus->ifs.values_num; i++)
+	{
+		ifstatus = (zbx_dc_ifstatus_t *)host_ifstatus->ifs.values[i];
+
+		if (HOST_AVAILABLE_UNSET == ifstatus->agent.available)
+		{
+			if (-1 == available[ifstatus->type])
+				available[ifstatus->type] = HOST_AVAILABLE_UNSET;
+			continue;
+		}
+
+		agent = &agents[ifstatus->type];
+
+		if (-1 == available[ifstatus->type])
+			available[ifstatus->type] = ifstatus->agent.available;
+		else
+			available[ifstatus->type] |= ifstatus->agent.available;
+
+		if ('\0' != *ifstatus->agent.error)
+		{
+			if (NULL == agent->error)
+				agent->error = zbx_dsprintf(agent->error, "%s", ifstatus->agent.error);
+			else
+				agent->error = zbx_strdcatf(agent->error, "\n%s", ifstatus->agent.error);
+		}
+	}
+
+	for (i = 0; i < ZBX_AGENT_MAX; i++)
+	{
+		if (-1 != available[i])
+			agents[i].available = available[i];
+	}
+}
+
+/******************************************************************************
+ *                                                                            *
+ * Function: dc_update_host_availability                                      *
+ *                                                                            *
+ * Purpose: updates host availability in configuration cache                  *
+ *                                                                            *
+ * Parameters: agent         - [IN] the agent status data to set              *
+ *             available     - [OUT] the agent availability                   *
+ *             disable_until - [OUT] the time until agent can be polled       *
+ *             errors_from   - [OUT] the time of the first error              *
+ *             error         - [OUT] the error description                    *
+ *             update        - [OUT] the updated agent status data            *
+ *                                                                            *
+ * Return value: Succeed if any field was updated.                            *
+ *                                                                            *
+ * Comments: Only the fields that are different are updated and corresponding *
+ *           update flags set.                                                *
+ *                                                                            *
+ ******************************************************************************/
+static int	dc_update_host_availability(const zbx_agent_status_t *agent, unsigned char *available,
+		const char **error, zbx_agent_status_update_t *update)
+{
+	const char	*agent_error;
+
+	if (HOST_AVAILABLE_UNSET == agent->available)
+		return FAIL;
+
+	update->flags = ZBX_AGENT_STATUS_NONE;
+
+	if (agent->available != *available)
+	{
+		*available = agent->available;
+		update->available = agent->available;
+		update->flags |= ZBX_AGENT_STATUS_AVAILABLE;
+	}
+
+	agent_error = ZBX_NULL2EMPTY_STR(agent->error);
+
+	if (0 != strcmp(agent_error, *error))
+	{
+		zbx_strpool_release(*error);
+		*error = zbx_strpool_intern(agent_error);
+		update->error = zbx_strdup(NULL, agent_error);
+		update->flags |= ZBX_AGENT_STATUS_ERROR;
+	}
+
+	return (ZBX_AGENT_STATUS_NONE == update->flags ? FAIL : SUCCEED);
+}
+
+/******************************************************************************
+ *                                                                            *
+ * Function: dc_create_agent_status_update                                    *
+ *                                                                            *
+ * Purpose: creates agent status update                                       *
+ *                                                                            *
+ * Parameters: hostid     - [IN] the host identifier                          *
+ *             src        - [IN] the agent status update to add               *
+ *             agent_type - [IN] the agent type (see ZBX_AGENT_ defines)      *
+ *                                                                            *
+ ******************************************************************************/
+static zbx_agent_status_update_t	*dc_create_agent_status_update(zbx_uint64_t hostid,
+		const zbx_agent_status_update_t *src, unsigned char agent_type)
+{
+	zbx_agent_status_update_t	*update;
+
+	update = (zbx_agent_status_update_t *)zbx_malloc(NULL, sizeof(zbx_agent_status_update_t));
+	update->hostid = hostid;
+	update->type = agent_type;
+	update->flags = src->flags;
+	update->available = src->available;
+	update->error = src->error;
+
+	return update;
+}
+
+/******************************************************************************
+ *                                                                            *
+ * Function: zbx_dc_get_host_availability_updates                             *
+ *                                                                            *
+ * Purpose: gets host availability changes                                    *
+ *                                                                            *
+ * Parameters: updates - [OUT] the host availability updates                  *
+ *                                                                            *
+ ******************************************************************************/
+int	zbx_dc_get_host_availability_updates(zbx_vector_ptr_t *updates)
+{
+	ZBX_DC_HOST			*host;
+	zbx_uint64_t			*phostid;
+	zbx_hashset_iter_t		iter;
+	zbx_agent_status_t		agents[ZBX_AGENT_MAX];
+	int				i, ret = FAIL;
+	zbx_agent_status_update_t	update;
+
+	LOCK_CACHE;
+
+	if (0 == config->hosts_availability.num_data)
+		goto out;
+
+	zbx_hashset_iter_reset(&config->hosts_availability, &iter);
+	while (NULL != (phostid = zbx_hashset_iter_next(&iter)))
+	{
+		if (NULL == (host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, phostid)))
+			continue;
+
+		memset(agents, 0, sizeof(agents));
+		dc_get_aggregate_host_availability(*phostid, agents);
+
+		if (SUCCEED == dc_update_host_availability(&agents[ZBX_AGENT_ZABBIX], &host->available, &host->error,
+				&update))
+		{
+			zbx_vector_ptr_append(updates, dc_create_agent_status_update(*phostid, &update, ZBX_AGENT_ZABBIX));
+		}
+
+		if (SUCCEED == dc_update_host_availability(&agents[ZBX_AGENT_SNMP], &host->snmp_available,
+				&host->snmp_error, &update))
+		{
+			zbx_vector_ptr_append(updates, dc_create_agent_status_update(*phostid, &update, ZBX_AGENT_SNMP));
+		}
+
+		if (SUCCEED == dc_update_host_availability(&agents[ZBX_AGENT_IPMI], &host->ipmi_available,
+				&host->ipmi_error, &update))
+		{
+			zbx_vector_ptr_append(updates, dc_create_agent_status_update(*phostid, &update, ZBX_AGENT_IPMI));
+		}
+
+		if (SUCCEED == dc_update_host_availability(&agents[ZBX_AGENT_JMX], &host->jmx_available,
+				&host->jmx_error, &update))
+		{
+			zbx_vector_ptr_append(updates, dc_create_agent_status_update(*phostid, &update, ZBX_AGENT_JMX));
+		}
+
+		for (i = 0; i < ZBX_AGENT_MAX; i++)
+			zbx_free(agents[i].error);
+	}
+
+	zbx_hashset_clear(&config->hosts_availability);
+
+	if (0 != updates->values_num)
+		ret = SUCCEED;
+out:
+	UNLOCK_CACHE;
+
+	return ret;
+}
+
+/******************************************************************************
+ *                                                                            *
+ * Function: zbx_refresh_host_availability                                    *
+ *                                                                            *
+ * Purpose: force host availability status refresh for the hosts in updates   *
+ *                                                                            *
+ ******************************************************************************/
+void	zbx_refresh_host_availability(const zbx_vector_ptr_t *updates)
+{
+	int				i;
+	zbx_uint64_t			hostid = 0;
+	const zbx_agent_status_update_t	*update;
+
+	LOCK_CACHE;
+
+	for (i = 0; i < updates->values_num; i++)
+	{
+		update = (const zbx_agent_status_update_t *)updates->values[i];
+
+		if (update->hostid == hostid)
+			continue;
+
+		hostid = update->hostid;
+		zbx_hashset_insert(&config->hosts_availability, &hostid, sizeof(hostid));
+	}
+
+	UNLOCK_CACHE;
+}
+
+void	zbx_dc_update_proxy_host_availability(const zbx_vector_ptr_t *updates)
+{
+	int				i, j;
+	zbx_uint64_t			hostid = 0;
+	const zbx_agent_status_update_t	*update;
+	zbx_dc_host_ifstatus_t		*host_ifstatus = NULL;
+	zbx_dc_ifstatus_t		*ifstatus;
+	const char			*error;
+
+	LOCK_CACHE;
+
+	for (i = 0; i < updates->values_num; i++)
+	{
+		update = (const zbx_agent_status_update_t *)updates->values[i];
+
+		if (update->hostid != hostid)
+		{
+			hostid = update->hostid;
+			host_ifstatus = (zbx_dc_host_ifstatus_t *)zbx_hashset_search(&config->hosts_ifstatus, &hostid);
+		}
+
+		if (NULL == host_ifstatus)
+			continue;
+
+		for (j = 0; j < host_ifstatus->ifs.values_num; j++)
+		{
+			ifstatus = (zbx_dc_ifstatus_t *)host_ifstatus->ifs.values[j];
+
+			if (update->type == ifstatus->type)
+			{
+				error = (0 != (update->flags & ZBX_AGENT_STATUS_ERROR) ? update->error : "");
+				dc_set_agent_status(hostid, &ifstatus->agent, update->available, 0, 0, error);
+				break;
+			}
+		}
+	}
+
+	UNLOCK_CACHE;
+}
+
+
+/******************************************************************************
+ *                                                                            *
+ * Function: zbx_dc_get_host_availability                                     *
+ *                                                                            *
+ * Purpose: returns host agent availability                                   *
+ *                                                                            *
+ * Parameter: hostid - [IN] the host identifier                               *
+ *            agents - [OUT] the agent availability data                      *
+ *                                                                            *
+ * Comments: The agent availability data might contain error message that has *
+ *           to be freed by the caller. Use zbx_dc_clean_host_availability()  *
+ *           function for it.                                                 *
+ *                                                                            *
+ ******************************************************************************/
+void	zbx_dc_get_host_availability(zbx_uint64_t hostid, zbx_agent_status_t *agents)
+{
+	ZBX_DC_HOST	*host;
+
+	memset(agents, 0, sizeof(zbx_agent_status_t) * ZBX_AGENT_MAX);
+
+	LOCK_CACHE;
+
+	if (NULL != (host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &hostid)))
+		 dc_get_aggregate_host_availability(hostid, agents);
+
+	UNLOCK_CACHE;
+}
+
+/******************************************************************************
+ *                                                                            *
+ * Function: zbx_dc_clean_host_availability                                   *
+ *                                                                            *
+ * Purpose: cleans host agent availability data returned by                   *
+ *          zbx_dc_get_host_availability                                      *
+ *                                                                            *
+ * Parameter: lastaccess - [OUT] last access updates for proxies that need    *
+ *                               to be synced with database, sorted by        *
+ *                               hostid                                       *
+ *                                                                            *
+ ******************************************************************************/
+void	zbx_dc_clean_host_availability(zbx_agent_status_t *agents)
+{
+	int	i;
+
+	for (i = 0; i < ZBX_AGENT_MAX; i++)
+	{
+		if (HOST_AVAILABLE_FALSE == agents[i].available)
+			zbx_free(agents[i].error);
+	}
+}
+
+/******************************************************************************
+ *                                                                            *
+ * Function: zbx_agent_status_update_free                                     *
+ *                                                                            *
+ * Purpose: frees agent status update data                                    *
+ *                                                                            *
+ ******************************************************************************/
+void	zbx_agent_status_update_free(void *data)
+{
+	zbx_agent_status_update_t	*update = (zbx_agent_status_update_t *)data;
+
+	if (0 != (update->flags & ZBX_AGENT_STATUS_ERROR))
+		zbx_free(update->error);
+	zbx_free(update);
+}
diff --git a/src/libs/zbxdbcache/dbconfig.h b/src/libs/zbxdbcache/dbconfig.h
index fb4e4f6..002f7bd 100644
--- a/src/libs/zbxdbcache/dbconfig.h
+++ b/src/libs/zbxdbcache/dbconfig.h
@@ -26,6 +26,25 @@
 
 typedef struct
 {
+	zbx_uint64_t		interfaceid;
+	zbx_hash_t		agent_hash;
+
+	int			refcount;
+	unsigned char		type;
+
+	zbx_agent_status_t	agent;
+}
+zbx_dc_ifstatus_t;
+
+typedef struct
+{
+	zbx_uint64_t		hostid;
+	zbx_vector_ptr_t	ifs;
+}
+zbx_dc_host_ifstatus_t;
+
+typedef struct
+{
 	zbx_uint64_t		triggerid;
 	const char		*description;
 	const char		*expression;
@@ -70,34 +89,35 @@ ZBX_DC_FUNCTION;
 
 typedef struct
 {
-	zbx_uint64_t		itemid;
-	zbx_uint64_t		hostid;
-	zbx_uint64_t		interfaceid;
-	zbx_uint64_t		lastlogsize;
-	zbx_uint64_t		valuemapid;
-	const char		*key;
-	const char		*port;
-	const char		*error;
-	const char		*delay;
-	ZBX_DC_TRIGGER		**triggers;
-	int			nextcheck;
-	int			lastclock;
-	int			mtime;
-	int			data_expected_from;
-	int			history_sec;
-	unsigned char		history;
-	unsigned char		type;
-	unsigned char		value_type;
-	unsigned char		poller_type;
-	unsigned char		state;
-	unsigned char		db_state;
-	unsigned char		inventory_link;
-	unsigned char		location;
-	unsigned char		flags;
-	unsigned char		status;
-	unsigned char		queue_priority;
-	unsigned char		schedulable;
-	unsigned char		update_triggers;
+	zbx_uint64_t			itemid;
+	zbx_uint64_t			hostid;
+	zbx_uint64_t			interfaceid;
+	zbx_uint64_t			lastlogsize;
+	zbx_uint64_t			valuemapid;
+	const char			*key;
+	const char			*port;
+	const char			*error;
+	const char			*delay;
+	ZBX_DC_TRIGGER			**triggers;
+	zbx_dc_ifstatus_t		*ifstatus;
+	int				nextcheck;
+	int				lastclock;
+	int				mtime;
+	int				data_expected_from;
+	int				history_sec;
+	unsigned char			history;
+	unsigned char			type;
+	unsigned char			value_type;
+	unsigned char			poller_type;
+	unsigned char			state;
+	unsigned char			db_state;
+	unsigned char			inventory_link;
+	unsigned char			location;
+	unsigned char			flags;
+	unsigned char			status;
+	unsigned char			queue_priority;
+	unsigned char			schedulable;
+	unsigned char			update_triggers;
 }
 ZBX_DC_ITEM;
 
@@ -284,14 +304,6 @@ typedef struct
 	const char	*name;
 	int		maintenance_from;
 	int		data_expected_from;
-	int		errors_from;
-	int		disable_until;
-	int		snmp_errors_from;
-	int		snmp_disable_until;
-	int		ipmi_errors_from;
-	int		ipmi_disable_until;
-	int		jmx_errors_from;
-	int		jmx_disable_until;
 
 	/* item statistics per interface type */
 	int		items_num;
@@ -299,9 +311,6 @@ typedef struct
 	int		ipmi_items_num;
 	int		jmx_items_num;
 
-	/* timestamp of last availability status (available/error) field change on any interface */
-	int		availability_ts;
-
 	unsigned char	maintenance_status;
 	unsigned char	maintenance_type;
 	unsigned char	available;
@@ -310,9 +319,6 @@ typedef struct
 	unsigned char	jmx_available;
 	unsigned char	status;
 
-	/* flag to reset host availability to unknown */
-	unsigned char	reset_availability;
-
 	/* flag to force update for all items */
 	unsigned char	update_items;
 
@@ -631,7 +637,6 @@ zbx_dc_preproc_op_t;
 typedef struct
 {
 	/* timestamp of the last host availability diff sent to sever, used only by proxies */
-	int			availability_diff_ts;
 	int			proxy_lastaccess_ts;
 	int			sync_ts;
 	int			item_sync_ts;
@@ -684,6 +689,8 @@ typedef struct
 	zbx_hashset_t		hostgroups;
 	zbx_vector_ptr_t	hostgroups_name; 	/* host groups sorted by name */
 	zbx_hashset_t		preprocops;
+	zbx_hashset_t		hosts_ifstatus;		/* interface status for passive items by hosts */
+	zbx_hashset_t		hosts_availability;	/* hostids with modified availability */
 #if defined(HAVE_POLARSSL) || defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
 	zbx_hashset_t		psks;			/* for keeping PSK-identity and PSK pairs and for searching */
 							/* by PSK identity */
diff --git a/src/libs/zbxdbcache/dbconfig_dump.c b/src/libs/zbxdbcache/dbconfig_dump.c
index 3260472..dbaf890 100644
--- a/src/libs/zbxdbcache/dbconfig_dump.c
+++ b/src/libs/zbxdbcache/dbconfig_dump.c
@@ -99,19 +99,14 @@ static void	DCdump_hosts(ZBX_DC_CONFIG *config)
 		zabbix_log(LOG_LEVEL_TRACE, "  proxy_hostid:%d", host->proxy_hostid);
 		zabbix_log(LOG_LEVEL_TRACE, "  data_expected_from:%d", host->data_expected_from);
 
-		zabbix_log(LOG_LEVEL_TRACE, "  zabbix:[available:%u, errors_from:%d disable_until:%d error:'%s']",
-				host->available, host->errors_from, host->disable_until, host->error);
-		zabbix_log(LOG_LEVEL_TRACE, "  snmp:[available:%u, errors_from:%d disable_until:%d error:'%s']",
-				host->snmp_available, host->snmp_errors_from, host->snmp_disable_until,
-				host->snmp_error);
-		zabbix_log(LOG_LEVEL_TRACE, "  ipmi:[available:%u, errors_from:%d disable_until:%d error:'%s']",
-				host->ipmi_available, host->ipmi_errors_from, host->ipmi_disable_until,
-				host->ipmi_error);
-		zabbix_log(LOG_LEVEL_TRACE, "  jmx:[available:%u, errors_from:%d disable_until:%d error:'%s']",
-				host->jmx_available, host->jmx_errors_from, host->jmx_disable_until, host->jmx_error);
-
-		/* timestamp of last availability status (available/error) field change on any interface */
-		zabbix_log(LOG_LEVEL_TRACE, "  availability_ts:%d", host->availability_ts);
+		zabbix_log(LOG_LEVEL_TRACE, "  zabbix:[available:%u, error:'%s']",
+				host->available, host->error);
+		zabbix_log(LOG_LEVEL_TRACE, "  snmp:[available:%u, error:'%s']",
+				host->snmp_available, host->snmp_error);
+		zabbix_log(LOG_LEVEL_TRACE, "  ipmi:[available:%u, error:'%s']",
+				host->ipmi_available, host->ipmi_error);
+		zabbix_log(LOG_LEVEL_TRACE, "  jmx:[available:%u, error:'%s']",
+				host->jmx_available, host->jmx_error);
 
 		zabbix_log(LOG_LEVEL_TRACE, "  maintenance_status:%u maintenance_type:%u maintenance_from:%d",
 				host->maintenance_status, host->maintenance_type, host->maintenance_from);
diff --git a/src/libs/zbxdbcache/dbsync.c b/src/libs/zbxdbcache/dbsync.c
index 05eae2a..2fdd542 100644
--- a/src/libs/zbxdbcache/dbsync.c
+++ b/src/libs/zbxdbcache/dbsync.c
@@ -505,7 +505,7 @@ static int	dbsync_compare_host(ZBX_DC_HOST *host, const DB_ROW dbrow)
 		return FAIL;
 	}
 
-	if (FAIL == dbsync_compare_uchar(dbrow[22], host->status))
+	if (FAIL == dbsync_compare_uchar(dbrow[14], host->status))
 	{
 		host->update_items = 1;
 		return FAIL;
@@ -516,17 +516,17 @@ static int	dbsync_compare_host(ZBX_DC_HOST *host, const DB_ROW dbrow)
 	if (FAIL == dbsync_compare_str(dbrow[2], host->host))
 		return FAIL;
 
-	if (FAIL == dbsync_compare_str(dbrow[23], host->name))
+	if (FAIL == dbsync_compare_str(dbrow[15], host->name))
 		return FAIL;
 
 #if defined(HAVE_POLARSSL) || defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
-	if (FAIL == dbsync_compare_str(dbrow[31], host->tls_issuer))
+	if (FAIL == dbsync_compare_str(dbrow[23], host->tls_issuer))
 		return FAIL;
 
-	if (FAIL == dbsync_compare_str(dbrow[32], host->tls_subject))
+	if (FAIL == dbsync_compare_str(dbrow[24], host->tls_subject))
 		return FAIL;
 
-	if ('\0' == *dbrow[33] || '\0' == *dbrow[34])
+	if ('\0' == *dbrow[25] || '\0' == *dbrow[26])
 	{
 		if (NULL != host->tls_dc_psk)
 			return FAIL;
@@ -536,18 +536,18 @@ static int	dbsync_compare_host(ZBX_DC_HOST *host, const DB_ROW dbrow)
 		if (NULL == host->tls_dc_psk)
 			return FAIL;
 
-		if (FAIL == dbsync_compare_str(dbrow[33], host->tls_dc_psk->tls_psk_identity))
+		if (FAIL == dbsync_compare_str(dbrow[25], host->tls_dc_psk->tls_psk_identity))
 			return FAIL;
 
-		if (FAIL == dbsync_compare_str(dbrow[34], host->tls_dc_psk->tls_psk))
+		if (FAIL == dbsync_compare_str(dbrow[26], host->tls_dc_psk->tls_psk))
 			return FAIL;
 	}
 
 #endif
-	if (FAIL == dbsync_compare_uchar(dbrow[29], host->tls_connect))
+	if (FAIL == dbsync_compare_uchar(dbrow[21], host->tls_connect))
 		return FAIL;
 
-	if (FAIL == dbsync_compare_uchar(dbrow[30], host->tls_accept))
+	if (FAIL == dbsync_compare_uchar(dbrow[22], host->tls_accept))
 		return FAIL;
 
 	/* IPMI hosts */
@@ -582,10 +582,10 @@ static int	dbsync_compare_host(ZBX_DC_HOST *host, const DB_ROW dbrow)
 	/* proxies */
 	if (NULL != (proxy = (ZBX_DC_PROXY *)zbx_hashset_search(&dbsync_env.cache->proxies, &host->hostid)))
 	{
-		if (FAIL == dbsync_compare_str(dbrow[31 + ZBX_HOST_TLS_OFFSET], proxy->proxy_address))
+		if (FAIL == dbsync_compare_str(dbrow[23 + ZBX_HOST_TLS_OFFSET], proxy->proxy_address))
 			return FAIL;
 
-		if (FAIL == dbsync_compare_uchar(dbrow[32 + ZBX_HOST_TLS_OFFSET], proxy->auto_compress))
+		if (FAIL == dbsync_compare_uchar(dbrow[24 + ZBX_HOST_TLS_OFFSET], proxy->auto_compress))
 			return FAIL;
 	}
 
@@ -618,9 +618,7 @@ int	zbx_dbsync_compare_hosts(zbx_dbsync_t *sync)
 	if (NULL == (result = DBselect(
 			"select hostid,proxy_hostid,host,ipmi_authtype,ipmi_privilege,ipmi_username,"
 				"ipmi_password,maintenance_status,maintenance_type,maintenance_from,"
-				"errors_from,available,disable_until,snmp_errors_from,"
-				"snmp_available,snmp_disable_until,ipmi_errors_from,ipmi_available,"
-				"ipmi_disable_until,jmx_errors_from,jmx_available,jmx_disable_until,"
+				"available,snmp_available,ipmi_available,jmx_available,"
 				"status,name,lastaccess,error,snmp_error,ipmi_error,jmx_error,tls_connect,tls_accept"
 				",tls_issuer,tls_subject,tls_psk_identity,tls_psk,proxy_address,auto_compress"
 			" from hosts"
@@ -633,14 +631,12 @@ int	zbx_dbsync_compare_hosts(zbx_dbsync_t *sync)
 		return FAIL;
 	}
 
-	dbsync_prepare(sync, 37, NULL);
+	dbsync_prepare(sync, 29, NULL);
 #else
 	if (NULL == (result = DBselect(
 			"select hostid,proxy_hostid,host,ipmi_authtype,ipmi_privilege,ipmi_username,"
 				"ipmi_password,maintenance_status,maintenance_type,maintenance_from,"
-				"errors_from,available,disable_until,snmp_errors_from,"
-				"snmp_available,snmp_disable_until,ipmi_errors_from,ipmi_available,"
-				"ipmi_disable_until,jmx_errors_from,jmx_available,jmx_disable_until,"
+				"available,snmp_available,ipmi_available,jmx_available,"
 				"status,name,lastaccess,error,snmp_error,ipmi_error,jmx_error,tls_connect,tls_accept,"
 				"proxy_address,auto_compress"
 			" from hosts"
@@ -653,7 +649,7 @@ int	zbx_dbsync_compare_hosts(zbx_dbsync_t *sync)
 		return FAIL;
 	}
 
-	dbsync_prepare(sync, 33, NULL);
+	dbsync_prepare(sync, 25, NULL);
 #endif
 
 	if (ZBX_DBSYNC_INIT == sync->mode)
diff --git a/src/libs/zbxdbcache/dbsync.h b/src/libs/zbxdbcache/dbsync.h
index 649d578..416bf50 100644
--- a/src/libs/zbxdbcache/dbsync.h
+++ b/src/libs/zbxdbcache/dbsync.h
@@ -142,5 +142,4 @@ int	zbx_dbsync_compare_corr_operations(zbx_dbsync_t *sync);
 int	zbx_dbsync_compare_host_groups(zbx_dbsync_t *sync);
 int	zbx_dbsync_compare_item_preprocs(zbx_dbsync_t *sync);
 
-
 #endif /* BUILD_SRC_LIBS_ZBXDBCACHE_DBSYNC_H_ */
diff --git a/src/libs/zbxdbhigh/db.c b/src/libs/zbxdbhigh/db.c
index 1e4ee18..966e0a5 100644
--- a/src/libs/zbxdbhigh/db.c
+++ b/src/libs/zbxdbhigh/db.c
@@ -2796,72 +2796,6 @@ int	DBlock_records(const char *table, const zbx_vector_uint64_t *ids)
 
 /******************************************************************************
  *                                                                            *
- * Function: zbx_sql_add_host_availability                                    *
- *                                                                            *
- * Purpose: adds host availability update to sql statement                    *
- *                                                                            *
- * Parameters: sql        - [IN/OUT] the sql statement                        *
- *             sql_alloc  - [IN/OUT] the number of bytes allocated for sql    *
- *                                   statement                                *
- *             sql_offset - [IN/OUT] the number of bytes used in sql          *
- *                                   statement                                *
- *             ha           [IN] the host availability data                   *
- *                                                                            *
- ******************************************************************************/
-int	zbx_sql_add_host_availability(char **sql, size_t *sql_alloc, size_t *sql_offset,
-		const zbx_host_availability_t *ha)
-{
-	const char	*field_prefix[ZBX_AGENT_MAX] = {"", "snmp_", "ipmi_", "jmx_"};
-	char		delim = ' ';
-	int		i;
-
-	if (FAIL == zbx_host_availability_is_set(ha))
-		return FAIL;
-
-	zbx_strcpy_alloc(sql, sql_alloc, sql_offset, "update hosts set");
-
-	for (i = 0; i < ZBX_AGENT_MAX; i++)
-	{
-		if (0 != (ha->agents[i].flags & ZBX_FLAGS_AGENT_STATUS_AVAILABLE))
-		{
-			zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%c%savailable=%d", delim, field_prefix[i],
-					(int)ha->agents[i].available);
-			delim = ',';
-		}
-
-		if (0 != (ha->agents[i].flags & ZBX_FLAGS_AGENT_STATUS_ERROR))
-		{
-			char	*error_esc;
-
-			error_esc = DBdyn_escape_field("hosts", "error", ha->agents[i].error);
-			zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%c%serror='%s'", delim, field_prefix[i],
-					error_esc);
-			zbx_free(error_esc);
-			delim = ',';
-		}
-
-		if (0 != (ha->agents[i].flags & ZBX_FLAGS_AGENT_STATUS_ERRORS_FROM))
-		{
-			zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%c%serrors_from=%d", delim, field_prefix[i],
-					ha->agents[i].errors_from);
-			delim = ',';
-		}
-
-		if (0 != (ha->agents[i].flags & ZBX_FLAGS_AGENT_STATUS_DISABLE_UNTIL))
-		{
-			zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%c%sdisable_until=%d", delim, field_prefix[i],
-					ha->agents[i].disable_until);
-			delim = ',';
-		}
-	}
-
-	zbx_snprintf_alloc(sql, sql_alloc, sql_offset, " where hostid=" ZBX_FS_UI64, ha->hostid);
-
-	return SUCCEED;
-}
-
-/******************************************************************************
- *                                                                            *
  * Function: DBget_user_by_active_session                                     *
  *                                                                            *
  * Purpose: validate that session is active and get associated user data      *
diff --git a/src/libs/zbxdbhigh/proxy.c b/src/libs/zbxdbhigh/proxy.c
index e33e1b1..11e3645 100644
--- a/src/libs/zbxdbhigh/proxy.c
+++ b/src/libs/zbxdbhigh/proxy.c
@@ -1480,7 +1480,7 @@ static int	process_proxyconfig_table(const ZBX_TABLE *table, struct zbx_json_par
 	{
 		zbx_vector_uint64_sort(&availability_hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
 		zbx_vector_uint64_uniq(&availability_hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
-		DCtouch_hosts_availability(&availability_hostids);
+		zbx_dc_refresh_hosts_availability(&availability_hostids);
 	}
 clean:
 	if (0 != ins.values_num)
@@ -1614,10 +1614,7 @@ void	process_proxyconfig(struct zbx_json_parse *jp_data)
 				(NULL == error ? "database error" : error));
 	}
 	else
-	{
 		DCsync_configuration(ZBX_DBSYNC_UPDATE);
-		DCupdate_hosts_availability();
-	}
 
 	zbx_free(error);
 
@@ -1632,45 +1629,47 @@ void	process_proxyconfig(struct zbx_json_parse *jp_data)
  *                FAIL - no host availability has been changed                *
  *                                                                            *
  ******************************************************************************/
-int	get_host_availability_data(struct zbx_json *json, int *ts)
+int	get_host_availability_data(struct zbx_json *json, zbx_vector_ptr_t *updates)
 {
 	const char			*__function_name = "get_host_availability_data";
-	int				i, j, ret = FAIL;
-	zbx_vector_ptr_t		hosts;
-	zbx_host_availability_t		*ha;
+	int				i, ret = FAIL;
+	zbx_agent_status_update_t	*update;
+	zbx_uint64_t			hostid = 0;
+	const char			*error;
 
 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
 
-	zbx_vector_ptr_create(&hosts);
-
-	if (SUCCEED != DCget_hosts_availability(&hosts, ts))
+	if (SUCCEED != zbx_dc_get_host_availability_updates(updates))
 		goto out;
 
 	zbx_json_addarray(json, ZBX_PROTO_TAG_HOST_AVAILABILITY);
 
-	for (i = 0; i < hosts.values_num; i++)
+	for (i = 0; i < updates->values_num; i++)
 	{
-		ha = (zbx_host_availability_t *)hosts.values[i];
+		update = (zbx_agent_status_update_t *)updates->values[i];
 
-		zbx_json_addobject(json, NULL);
-		zbx_json_adduint64(json, ZBX_PROTO_TAG_HOSTID, ha->hostid);
-
-		for (j = 0; j < ZBX_AGENT_MAX; j++)
+		if (update->hostid != hostid)
 		{
-			zbx_json_adduint64(json, availability_tag_available[j], ha->agents[j].available);
-			zbx_json_addstring(json, availability_tag_error[j], ha->agents[j].error, ZBX_JSON_TYPE_STRING);
+			if (0 != hostid)
+				zbx_json_close(json);
+
+			zbx_json_addobject(json, NULL);
+			zbx_json_adduint64(json, ZBX_PROTO_TAG_HOSTID, update->hostid);
+
+			hostid = update->hostid;
 		}
 
-		zbx_json_close(json);
+		error = (HOST_AVAILABLE_FALSE == update->available ? update->error : "");
+
+		zbx_json_adduint64(json, availability_tag_available[update->type], update->available);
+		zbx_json_addstring(json, availability_tag_error[update->type], error, ZBX_JSON_TYPE_STRING);
 	}
 
 	zbx_json_close(json);
+	zbx_json_close(json);
 
 	ret = SUCCEED;
 out:
-	zbx_vector_ptr_clear_ext(&hosts, (zbx_mem_free_func_t)zbx_host_availability_free);
-	zbx_vector_ptr_destroy(&hosts);
-
 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
 
 	return ret;
@@ -1688,18 +1687,18 @@ out:
  ******************************************************************************/
 static int	process_host_availability_contents(struct zbx_json_parse *jp_data, char **error)
 {
-	zbx_uint64_t		hostid;
-	struct zbx_json_parse	jp_row;
-	const char		*p = NULL;
-	char			*tmp = NULL;
-	size_t			tmp_alloc = 129;
-	zbx_host_availability_t	*ha = NULL;
-	zbx_vector_ptr_t	hosts;
-	int			i, ret;
+	zbx_uint64_t			hostid;
+	struct zbx_json_parse		jp_row;
+	const char			*p = NULL;
+	char				*tmp = NULL;
+	size_t				tmp_alloc = 129;
+	zbx_agent_status_update_t	*update;
+	zbx_vector_ptr_t		updates;
+	int				i, ret;
 
 	tmp = (char *)zbx_malloc(NULL, tmp_alloc);
 
-	zbx_vector_ptr_create(&hosts);
+	zbx_vector_ptr_create(&updates);
 
 	while (NULL != (p = zbx_json_next(jp_data, p)))	/* iterate the host entries */
 	{
@@ -1721,9 +1720,6 @@ static int	process_host_availability_contents(struct zbx_json_parse *jp_data, ch
 			goto out;
 		}
 
-		ha = (zbx_host_availability_t *)zbx_malloc(NULL, sizeof(zbx_host_availability_t));
-		zbx_host_availability_init(ha, hostid);
-
 		for (i = 0; i < ZBX_AGENT_MAX; i++)
 		{
 			if (SUCCEED != zbx_json_value_by_name_dyn(&jp_row, availability_tag_available[i], &tmp,
@@ -1732,62 +1728,29 @@ static int	process_host_availability_contents(struct zbx_json_parse *jp_data, ch
 				continue;
 			}
 
-			ha->agents[i].available = atoi(tmp);
-			ha->agents[i].flags |= ZBX_FLAGS_AGENT_STATUS_AVAILABLE;
-		}
-
-		for (i = 0; i < ZBX_AGENT_MAX; i++)
-		{
-			if (SUCCEED != zbx_json_value_by_name_dyn(&jp_row, availability_tag_error[i], &tmp, &tmp_alloc))
-				continue;
+			update = (zbx_agent_status_update_t *)zbx_malloc(NULL, sizeof(zbx_agent_status_update_t));
+			update->hostid = hostid;
+			update->flags = ZBX_AGENT_STATUS_AVAILABLE;
+			update->type = i;
+			update->available = atoi(tmp);
 
-			ha->agents[i].error = zbx_strdup(NULL, tmp);
-			ha->agents[i].flags |= ZBX_FLAGS_AGENT_STATUS_ERROR;
-		}
+			if (SUCCEED == zbx_json_value_by_name_dyn(&jp_row, availability_tag_error[i], &tmp, &tmp_alloc))
+			{
+				update->flags |= ZBX_AGENT_STATUS_ERROR;
+				update->error = zbx_strdup(NULL, tmp);
+			}
 
-		if (SUCCEED != (ret = zbx_host_availability_is_set(ha)))
-		{
-			zbx_free(ha);
-			*error = zbx_dsprintf(*error, "no availability data for \"hostid\":" ZBX_FS_UI64, hostid);
-			goto out;
+			zbx_vector_ptr_append(&updates, update);
 		}
-
-		zbx_vector_ptr_append(&hosts, ha);
 	}
 
-	if (0 < hosts.values_num && SUCCEED == DCset_hosts_availability(&hosts))
-	{
-		int	i;
-		char	*sql = NULL;
-		size_t	sql_alloc = 4 * ZBX_KIBIBYTE, sql_offset = 0;
-
-		sql = (char *)zbx_malloc(sql, sql_alloc);
-
-		DBbegin();
-		DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
-
-		for (i = 0; i < hosts.values_num; i++)
-		{
-			if (SUCCEED == zbx_sql_add_host_availability(&sql, &sql_alloc, &sql_offset, (zbx_host_availability_t *)hosts.values[i]))
-				zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
-
-			DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset);
-		}
-
-		DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
-
-		if (16 < sql_offset)
-			DBexecute("%s", sql);
-
-		DBcommit();
-
-		zbx_free(sql);
-	}
+	if (0 != updates.values_num)
+		zbx_dc_update_proxy_host_availability(&updates);
 
 	ret = SUCCEED;
 out:
-	zbx_vector_ptr_clear_ext(&hosts, (zbx_mem_free_func_t)zbx_host_availability_free);
-	zbx_vector_ptr_destroy(&hosts);
+	zbx_vector_ptr_clear_ext(&updates, zbx_agent_status_update_free);
+	zbx_vector_ptr_destroy(&updates);
 
 	zbx_free(tmp);
 
diff --git a/src/libs/zbxself/selfmon.c b/src/libs/zbxself/selfmon.c
index 6b53782..bca7f91 100644
--- a/src/libs/zbxself/selfmon.c
+++ b/src/libs/zbxself/selfmon.c
@@ -115,6 +115,7 @@ extern int	CONFIG_IPMIMANAGER_FORKS;
 extern int	CONFIG_ALERTMANAGER_FORKS;
 extern int	CONFIG_PREPROCMAN_FORKS;
 extern int	CONFIG_PREPROCESSOR_FORKS;
+extern int	CONFIG_AVAILABILITYSYNCER_FORKS;
 
 extern unsigned char	process_type;
 extern int		process_num;
@@ -192,6 +193,8 @@ int	get_process_type_forks(unsigned char proc_type)
 			return CONFIG_PREPROCMAN_FORKS;
 		case ZBX_PROCESS_TYPE_PREPROCESSOR:
 			return CONFIG_PREPROCESSOR_FORKS;
+		case ZBX_PROCESS_TYPE_AVAILABILITY_SYNCER:
+			return CONFIG_AVAILABILITYSYNCER_FORKS;
 	}
 
 	THIS_SHOULD_NEVER_HAPPEN;
diff --git a/src/zabbix_agent/zabbix_agentd.c b/src/zabbix_agent/zabbix_agentd.c
index 0e39c20..9e95a32 100644
--- a/src/zabbix_agent/zabbix_agentd.c
+++ b/src/zabbix_agent/zabbix_agentd.c
@@ -266,6 +266,7 @@ int	CONFIG_IPMIMANAGER_FORKS	= 0;
 int	CONFIG_ALERTMANAGER_FORKS	= 0;
 int	CONFIG_PREPROCMAN_FORKS		= 0;
 int	CONFIG_PREPROCESSOR_FORKS	= 0;
+int	CONFIG_AVAILABILITYSYNCER_FORKS	= 0;
 
 char	*opt = NULL;
 
diff --git a/src/zabbix_proxy/datasender/datasender.c b/src/zabbix_proxy/datasender/datasender.c
index 91761ee..5a327d9 100644
--- a/src/zabbix_proxy/datasender/datasender.c
+++ b/src/zabbix_proxy/datasender/datasender.c
@@ -64,15 +64,17 @@ static int	proxy_data_sender(int *more, int now)
 	zbx_socket_t		sock;
 	struct zbx_json		j;
 	struct zbx_json_parse	jp, jp_tasks;
-	int			availability_ts, history_records = 0, discovery_records = 0,
+	int			history_records = 0, discovery_records = 0,
 				areg_records = 0, more_history = 0, more_discovery = 0, more_areg = 0;
 	zbx_uint64_t		history_lastid = 0, discovery_lastid = 0, areg_lastid = 0, flags = 0;
 	zbx_timespec_t		ts;
 	char			*error = NULL;
-	zbx_vector_ptr_t	tasks;
+	zbx_vector_ptr_t	tasks, availability;
 
 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
 
+	zbx_vector_ptr_create(&availability);
+
 	*more = ZBX_PROXY_DATA_DONE;
 	zbx_json_init(&j, 16 * ZBX_KIBIBYTE);
 
@@ -81,7 +83,7 @@ static int	proxy_data_sender(int *more, int now)
 
 	if (SUCCEED == upload_state && CONFIG_PROXYDATA_FREQUENCY <= now - data_timestamp)
 	{
-		if (SUCCEED == get_host_availability_data(&j, &availability_ts))
+		if (SUCCEED == get_host_availability_data(&j, &availability))
 			flags |= ZBX_DATASENDER_AVAILABILITY;
 
 		if  (0 != (history_records = proxy_get_hist_data(&j, &history_lastid, &more_history)))
@@ -143,12 +145,12 @@ static int	proxy_data_sender(int *more, int now)
 			zabbix_log(LOG_LEVEL_WARNING, "cannot send proxy data to server at \"%s\": %s",
 					sock.peer, error);
 			zbx_free(error);
+
+			if (0 != (flags & ZBX_DATASENDER_AVAILABILITY))
+				zbx_refresh_host_availability(&availability);
 		}
 		else
 		{
-			if (0 != (flags & ZBX_DATASENDER_AVAILABILITY))
-				zbx_set_availability_diff_ts(availability_ts);
-
 			if (SUCCEED == zbx_json_open(sock.buffer, &jp))
 			{
 				if (SUCCEED == zbx_json_brackets_by_name(&jp, ZBX_PROTO_TAG_TASKS, &jp_tasks))
@@ -190,6 +192,9 @@ static int	proxy_data_sender(int *more, int now)
 	zbx_vector_ptr_clear_ext(&tasks, (zbx_clean_func_t)zbx_tm_task_free);
 	zbx_vector_ptr_destroy(&tasks);
 
+	zbx_vector_ptr_clear_ext(&availability, zbx_agent_status_update_free);
+	zbx_vector_ptr_destroy(&availability);
+
 	zbx_json_free(&j);
 
 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s more:%d flags:0x" ZBX_FS_UX64, __function_name,
diff --git a/src/zabbix_proxy/proxy.c b/src/zabbix_proxy/proxy.c
index eb12322..a097219 100644
--- a/src/zabbix_proxy/proxy.c
+++ b/src/zabbix_proxy/proxy.c
@@ -162,6 +162,7 @@ int	CONFIG_IPMIMANAGER_FORKS	= 0;
 int	CONFIG_ALERTMANAGER_FORKS	= 0;
 int	CONFIG_PREPROCMAN_FORKS		= 0;
 int	CONFIG_PREPROCESSOR_FORKS	= 0;
+int	CONFIG_AVAILABILITYSYNCER_FORKS	= 1;
 
 int	CONFIG_LISTEN_PORT		= ZBX_DEFAULT_SERVER_PORT;
 char	*CONFIG_LISTEN_IP		= NULL;
diff --git a/src/zabbix_server/Makefile.am b/src/zabbix_server/Makefile.am
index 4348e31..bd45fe4 100644
--- a/src/zabbix_server/Makefile.am
+++ b/src/zabbix_server/Makefile.am
@@ -20,7 +20,8 @@ SUBDIRS = \
 	ipmi \
 	odbc \
 	scripts \
-	preprocessor
+	preprocessor \
+	availability
 
 sbin_PROGRAMS = zabbix_server
 
@@ -62,6 +63,7 @@ zabbix_server_LDADD = \
 	odbc/libzbxodbc.a \
 	scripts/libzbxscripts.a \
 	preprocessor/libpreprocessor.a \
+	availability/libzbxavailability.a \
 	$(top_srcdir)/src/libs/zbxsysinfo/libzbxserversysinfo.a \
 	$(top_srcdir)/src/libs/zbxsysinfo/common/libcommonsysinfo.a \
 	$(top_srcdir)/src/libs/zbxsysinfo/simple/libsimplesysinfo.a \
diff --git a/src/zabbix_server/availability/Makefile.am b/src/zabbix_server/availability/Makefile.am
new file mode 100644
index 0000000..ec2a94e
--- /dev/null
+++ b/src/zabbix_server/availability/Makefile.am
@@ -0,0 +1,5 @@
+## Process this file with automake to produce Makefile.in
+
+noinst_LIBRARIES = libzbxavailability.a
+
+libzbxavailability_a_SOURCES = availability.c availability.h
diff --git a/src/zabbix_server/availability/availability.c b/src/zabbix_server/availability/availability.c
new file mode 100644
index 0000000..eb23790
--- /dev/null
+++ b/src/zabbix_server/availability/availability.c
@@ -0,0 +1,197 @@
+/*
+** Zabbix
+** Copyright (C) 2001-2018 Zabbix SIA
+**
+** 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
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+**/
+
+#include "common.h"
+
+#include "db.h"
+#include "dbcache.h"
+#include "log.h"
+#include "daemon.h"
+#include "zbxself.h"
+
+#include "availability.h"
+#include "export.h"
+
+#define ZBX_AVAILABILITY_SYNCER_DELAY		1
+extern unsigned char	process_type, program_type;
+extern int		server_num, process_num;
+
+static int	db_flush_host_availability(const zbx_vector_ptr_t *updates)
+{
+	int		i;
+	char		*sql = NULL, delim, *error_esc, *agents[] = {"", "snmp_", "ipmi_", "jmx_"};
+	size_t		sql_alloc = 0, sql_offset = 0;
+	zbx_uint64_t	hostid;
+
+
+	DBbegin();
+	DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
+
+	delim = ' ';
+	hostid = ((const zbx_agent_status_update_t *)updates->values[0])->hostid;
+	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update hosts set");
+
+	for (i = 0; i < updates->values_num; i++)
+	{
+		const zbx_agent_status_update_t	*update = (const zbx_agent_status_update_t *)updates->values[i];
+
+		if (hostid != update->hostid)
+		{
+			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " where hostid=" ZBX_FS_UI64 ";\n", hostid);
+			if (SUCCEED != DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset))
+				goto out;
+
+			delim = ' ';
+			hostid = update->hostid;
+			zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update hosts set");
+		}
+
+		if (0 != (update->flags & ZBX_AGENT_STATUS_AVAILABLE))
+		{
+			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%c%savailable=%d", delim,
+					agents[update->type], update->available);
+			delim = ',';
+		}
+
+		if (0 != (update->flags & ZBX_AGENT_STATUS_ERROR))
+		{
+			error_esc = DBdyn_escape_string_len(update->error, HOST_ERROR_LEN);
+			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%c%serror='%s'", delim,
+					agents[update->type], error_esc);
+			delim = ',';
+			zbx_free(error_esc);
+		}
+	}
+
+	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " where hostid=" ZBX_FS_UI64 ";\n", hostid);
+	if (SUCCEED != DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset))
+		goto out;
+
+	DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
+
+
+	if (16 < sql_offset)
+		DBexecute("%s", sql);
+
+out:
+	zbx_free(sql);
+
+	return DBcommit();
+}
+
+static int	sync_availability()
+{
+	zbx_vector_ptr_t	updates;
+	int			ret = 0;
+
+	zbx_vector_ptr_create(&updates);
+	if (SUCCEED != zbx_dc_get_host_availability_updates(&updates))
+		goto out;
+
+	ret = updates.values_num;
+
+	zbx_vector_ptr_sort(&updates, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
+
+	while (ZBX_DB_DOWN == db_flush_host_availability(&updates))
+		;
+
+	zbx_vector_ptr_clear_ext(&updates, zbx_agent_status_update_free);
+out:
+	zbx_vector_ptr_destroy(&updates);
+
+	return ret;
+}
+
+/******************************************************************************
+ *                                                                            *
+ * Function: availability_syncer                                              *
+ *                                                                            *
+ * Purpose: periodically synchronizes cached host availability data with      *
+ *          database.                                                         *
+ *                                                                            *
+ ******************************************************************************/
+ZBX_THREAD_ENTRY(availability_syncer_thread, args)
+{
+	int	sleeptime = -1, num = 0, old_num = 0, sync_num;
+	double	sec, total_sec = 0.0, old_total_sec = 0.0;
+	time_t	last_stat_time;
+
+	process_type = ((zbx_thread_args_t *)args)->process_type;
+	server_num = ((zbx_thread_args_t *)args)->server_num;
+	process_num = ((zbx_thread_args_t *)args)->process_num;
+
+	zabbix_log(LOG_LEVEL_INFORMATION, "%s #%d started [%s #%d]", get_program_type_string(program_type),
+			server_num, get_process_type_string(process_type), process_num);
+
+#define STAT_INTERVAL	5	/* if a process is busy and does not sleep then update status not faster than */
+				/* once in STAT_INTERVAL seconds */
+
+	zbx_setproctitle("%s #%d [connecting to the database]", get_process_type_string(process_type), process_num);
+	last_stat_time = time(NULL);
+
+	DBconnect(ZBX_DB_CONNECT_NORMAL);
+
+	for (;;)
+	{
+		zbx_handle_log();
+
+		if (0 != sleeptime)
+		{
+			zbx_setproctitle("%s #%d [synced %d hosts in " ZBX_FS_DBL " sec, syncing availability]",
+					get_process_type_string(process_type), process_num, old_num, old_total_sec);
+		}
+
+		sec = zbx_time();
+
+		sync_num = sync_availability();
+
+		num += sync_num;
+		total_sec += zbx_time() - sec;
+
+		sleeptime = ZBX_AVAILABILITY_SYNCER_DELAY;
+
+		if (0 != sleeptime || STAT_INTERVAL <= time(NULL) - last_stat_time)
+		{
+			if (0 == sleeptime)
+			{
+				zbx_setproctitle("%s #%d [synced %d hosts in " ZBX_FS_DBL " sec, syncing availability]",
+						get_process_type_string(process_type), process_num, num, total_sec);
+			}
+			else
+			{
+				zbx_setproctitle("%s #%d [synced %d hosts in " ZBX_FS_DBL " sec, idle %d sec]",
+						get_process_type_string(process_type), process_num, num, total_sec,
+						sleeptime);
+				old_num = num;
+				old_total_sec = total_sec;
+			}
+			num = 0;
+			total_sec = 0.0;
+			last_stat_time = time(NULL);
+		}
+
+		zbx_sleep_loop(sleeptime);
+
+#if !defined(_WINDOWS) && defined(HAVE_RESOLV_H)
+		zbx_update_resolver_conf();	/* handle /etc/resolv.conf update */
+#endif
+	}
+
+#undef STAT_INTERVAL
+}
diff --git a/src/zabbix_server/availability/availability.h b/src/zabbix_server/availability/availability.h
new file mode 100644
index 0000000..c6e9ac0
--- /dev/null
+++ b/src/zabbix_server/availability/availability.h
@@ -0,0 +1,27 @@
+/*
+** Zabbix
+** Copyright (C) 2001-2018 Zabbix SIA
+**
+** 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
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+**/
+
+#ifndef ZABBIX_AVAILABILITY_H
+#define ZABBIX_AVAILABILITY_H
+
+#include "threads.h"
+
+ZBX_THREAD_ENTRY(availability_syncer_thread, args);
+
+#endif
diff --git a/src/zabbix_server/dbconfig/dbconfig.c b/src/zabbix_server/dbconfig/dbconfig.c
index 4e3df16..631b792 100644
--- a/src/zabbix_server/dbconfig/dbconfig.c
+++ b/src/zabbix_server/dbconfig/dbconfig.c
@@ -91,7 +91,7 @@ ZBX_THREAD_ENTRY(dbconfig_thread, args)
 
 		sec = zbx_time();
 		DCsync_configuration(ZBX_DBSYNC_UPDATE);
-		DCupdate_hosts_availability();
+		zbx_dc_reset_proxy_hosts_availability();
 		dc_flush_history();	/* misconfigured items generate pseudo-historic values to become notsupported */
 		sec = zbx_time() - sec;
 
diff --git a/src/zabbix_server/poller/checks_internal.c b/src/zabbix_server/poller/checks_internal.c
index d6f5892..0488042 100644
--- a/src/zabbix_server/poller/checks_internal.c
+++ b/src/zabbix_server/poller/checks_internal.c
@@ -342,23 +342,41 @@ int	get_value_internal(DC_ITEM *item, AGENT_RESULT *result)
 
 		if (0 == strcmp(tmp, "available"))		/* zabbix["host",<type>,"available"] */
 		{
+			zbx_agent_status_t	agents[ZBX_AGENT_MAX];
+			int			index = -1;
+
 			tmp = get_rparam(&request, 1);
 
 			if (0 == strcmp(tmp, "agent"))
-				SET_UI64_RESULT(result, item->host.available);
+				index = ZBX_AGENT_ZABBIX;
 			else if (0 == strcmp(tmp, "snmp"))
-				SET_UI64_RESULT(result, item->host.snmp_available);
+				index = ZBX_AGENT_SNMP;
 			else if (0 == strcmp(tmp, "ipmi"))
-				SET_UI64_RESULT(result, item->host.ipmi_available);
+				index = ZBX_AGENT_IPMI;
 			else if (0 == strcmp(tmp, "jmx"))
-				SET_UI64_RESULT(result, item->host.jmx_available);
+				index = ZBX_AGENT_JMX;
 			else
 			{
 				SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
 				goto out;
 			}
 
-			result->ui64 = 2 - result->ui64;
+			zbx_dc_get_host_availability(item->host.hostid, agents);
+
+			switch (agents[index].available)
+			{
+				case HOST_AVAILABLE_TRUE:
+					SET_UI64_RESULT(result, 1);
+					break;
+				case HOST_AVAILABLE_FALSE:
+					SET_UI64_RESULT(result, 0);
+					break;
+				case HOST_AVAILABLE_UNKNOWN:
+					SET_UI64_RESULT(result, 2);
+					break;
+			}
+
+			zbx_dc_clean_host_availability(agents);
 		}
 		else if (0 == strcmp(tmp, "maintenance"))	/* zabbix["host",,"maintenance"] */
 		{
diff --git a/src/zabbix_server/poller/poller.c b/src/zabbix_server/poller/poller.c
index 0fe160b..f94c177 100644
--- a/src/zabbix_server/poller/poller.c
+++ b/src/zabbix_server/poller/poller.c
@@ -48,211 +48,21 @@
 extern unsigned char	process_type, program_type;
 extern int		server_num, process_num;
 
-/******************************************************************************
- *                                                                            *
- * Function: db_host_update_availability                                      *
- *                                                                            *
- * Purpose: write host availability changes into database                     *
- *                                                                            *
- * Parameters: ha    - [IN] the host availability data                        *
- *                                                                            *
- * Return value: SUCCEED - the availability changes were written into db      *
- *               FAIL    - no changes in availability data were detected      *
- *                                                                            *
- ******************************************************************************/
-static int	db_host_update_availability(const zbx_host_availability_t *ha)
-{
-	char	*sql = NULL;
-	size_t	sql_alloc = 0, sql_offset = 0;
-
-	if (SUCCEED == zbx_sql_add_host_availability(&sql, &sql_alloc, &sql_offset, ha))
-	{
-		DBbegin();
-		DBexecute("%s", sql);
-		DBcommit();
-
-		zbx_free(sql);
-
-		return SUCCEED;
-	}
-
-	return FAIL;
-}
-
-/******************************************************************************
- *                                                                            *
- * Function: host_get_availability                                            *
- *                                                                            *
- * Purpose: get host availability data based on the specified agent type      *
- *                                                                            *
- * Parameters: dc_host      - [IN] the host                                   *
- *             type         - [IN] the agent type                             *
- *             availability - [OUT] the host availability data                *
- *                                                                            *
- * Return value: SUCCEED - the host availability data was retrieved           *
- *                         successfully                                       *
- *               FAIL    - failed to retrieve host availability data,         *
- *                         invalid agent type was specified                   *
- *                                                                            *
- ******************************************************************************/
-static int	host_get_availability(const DC_HOST *dc_host, unsigned char agent, zbx_host_availability_t *ha)
-{
-	zbx_agent_availability_t	*availability = &ha->agents[agent];
-
-	availability->flags = ZBX_FLAGS_AGENT_STATUS;
-
-	switch (agent)
-	{
-		case ZBX_AGENT_ZABBIX:
-			availability->available = dc_host->available;
-			availability->error = zbx_strdup(NULL, dc_host->error);
-			availability->errors_from = dc_host->errors_from;
-			availability->disable_until = dc_host->disable_until;
-			break;
-		case ZBX_AGENT_SNMP:
-			availability->available = dc_host->snmp_available;
-			availability->error = zbx_strdup(NULL, dc_host->snmp_error);
-			availability->errors_from = dc_host->snmp_errors_from;
-			availability->disable_until = dc_host->snmp_disable_until;
-			break;
-		case ZBX_AGENT_IPMI:
-			availability->available = dc_host->ipmi_available;
-			availability->error = zbx_strdup(NULL, dc_host->ipmi_error);
-			availability->errors_from = dc_host->ipmi_errors_from;
-			availability->disable_until = dc_host->ipmi_disable_until;
-			break;
-		case ZBX_AGENT_JMX:
-			availability->available = dc_host->jmx_available;
-			availability->error = zbx_strdup(NULL, dc_host->jmx_error);
-			availability->disable_until = dc_host->jmx_disable_until;
-			availability->errors_from = dc_host->jmx_errors_from;
-			break;
-		default:
-			return FAIL;
-	}
-
-	ha->hostid = dc_host->hostid;
-
-	return SUCCEED;
-}
-
-/******************************************************************************
- *                                                                            *
- * Function: host_set_availability                                            *
- *                                                                            *
- * Purpose: sets host availability data based on the specified agent type     *
- *                                                                            *
- * Parameters: dc_host      - [IN] the host                                   *
- *             type         - [IN] the agent type                             *
- *             availability - [IN] the host availability data                 *
- *                                                                            *
- * Return value: SUCCEED - the host availability data was set successfully    *
- *               FAIL    - failed to set host availability data,              *
- *                         invalid agent type was specified                   *
- *                                                                            *
- ******************************************************************************/
-static int	host_set_availability(DC_HOST *dc_host, unsigned char agent, const zbx_host_availability_t *ha)
-{
-	const zbx_agent_availability_t	*availability = &ha->agents[agent];
-	unsigned char			*pavailable;
-	int				*perrors_from, *pdisable_until;
-	char				*perror;
-
-	switch (agent)
-	{
-		case ZBX_AGENT_ZABBIX:
-			pavailable = &dc_host->available;
-			perror = dc_host->error;
-			perrors_from = &dc_host->errors_from;
-			pdisable_until = &dc_host->disable_until;
-			break;
-		case ZBX_AGENT_SNMP:
-			pavailable = &dc_host->snmp_available;
-			perror = dc_host->snmp_error;
-			perrors_from = &dc_host->snmp_errors_from;
-			pdisable_until = &dc_host->snmp_disable_until;
-			break;
-		case ZBX_AGENT_IPMI:
-			pavailable = &dc_host->ipmi_available;
-			perror = dc_host->ipmi_error;
-			perrors_from = &dc_host->ipmi_errors_from;
-			pdisable_until = &dc_host->ipmi_disable_until;
-			break;
-		case ZBX_AGENT_JMX:
-			pavailable = &dc_host->jmx_available;
-			perror = dc_host->jmx_error;
-			pdisable_until = &dc_host->jmx_disable_until;
-			perrors_from = &dc_host->jmx_errors_from;
-			break;
-		default:
-			return FAIL;
-	}
-
-	if (0 != (availability->flags & ZBX_FLAGS_AGENT_STATUS_AVAILABLE))
-		*pavailable = availability->available;
-
-	if (0 != (availability->flags & ZBX_FLAGS_AGENT_STATUS_ERROR))
-		zbx_strlcpy(perror, availability->error, HOST_ERROR_LEN_MAX);
-
-	if (0 != (availability->flags & ZBX_FLAGS_AGENT_STATUS_ERRORS_FROM))
-		*perrors_from = availability->errors_from;
-
-	if (0 != (availability->flags & ZBX_FLAGS_AGENT_STATUS_DISABLE_UNTIL))
-		*pdisable_until = availability->disable_until;
-
-	return SUCCEED;
-}
-
-static unsigned char	host_availability_agent_by_item_type(unsigned char type)
-{
-	switch (type)
-	{
-		case ITEM_TYPE_ZABBIX:
-			return ZBX_AGENT_ZABBIX;
-			break;
-		case ITEM_TYPE_SNMPv1:
-		case ITEM_TYPE_SNMPv2c:
-		case ITEM_TYPE_SNMPv3:
-			return ZBX_AGENT_SNMP;
-			break;
-		case ITEM_TYPE_IPMI:
-			return ZBX_AGENT_IPMI;
-			break;
-		case ITEM_TYPE_JMX:
-			return ZBX_AGENT_JMX;
-			break;
-		default:
-			return ZBX_AGENT_UNKNOWN;
-	}
-}
-
-void	zbx_activate_item_host(DC_ITEM *item, zbx_timespec_t *ts)
+void	zbx_activate_item_host(DC_ITEM *item)
 {
 	const char		*__function_name = "zbx_activate_item_host";
-	zbx_host_availability_t	in, out;
-	unsigned char		agent_type;
+	unsigned int		flags;
 
 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() hostid:" ZBX_FS_UI64 " itemid:" ZBX_FS_UI64 " type:%d",
 			__function_name, item->host.hostid, item->itemid, (int)item->type);
 
-	zbx_host_availability_init(&in, item->host.hostid);
-	zbx_host_availability_init(&out, item->host.hostid);
-
-	if (ZBX_AGENT_UNKNOWN == (agent_type = host_availability_agent_by_item_type(item->type)))
-		goto out;
-
-	if (FAIL == host_get_availability(&item->host, agent_type, &in))
+	if (ZBX_AGENT_STATUS_NONE == (flags = zbx_dc_item_activate(item)))
 		goto out;
 
-	if (FAIL == DChost_activate(item->host.hostid, agent_type, ts, &in.agents[agent_type], &out.agents[agent_type]))
+	if (HOST_AVAILABLE_UNSET == item->agent.available || HOST_AVAILABLE_UNKNOWN == item->agent.available)
 		goto out;
 
-	if (FAIL == db_host_update_availability(&out))
-		goto out;
-
-	host_set_availability(&item->host, agent_type, &out);
-
-	if (HOST_AVAILABLE_TRUE == in.agents[agent_type].available)
+	if (0 == (flags & ZBX_AGENT_STATUS_AVAILABLE))
 	{
 		zabbix_log(LOG_LEVEL_WARNING, "resuming %s checks on host \"%s\": connection restored",
 				zbx_agent_type_string(item->type), item->host.host);
@@ -263,58 +73,40 @@ void	zbx_activate_item_host(DC_ITEM *item, zbx_timespec_t *ts)
 				zbx_agent_type_string(item->type), item->host.host);
 	}
 out:
-	zbx_host_availability_clean(&out);
-	zbx_host_availability_clean(&in);
-
 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
 }
 
 void	zbx_deactivate_item_host(DC_ITEM *item, zbx_timespec_t *ts, const char *error)
 {
 	const char		*__function_name = "zbx_deactivate_item_host";
-	zbx_host_availability_t	in, out;
-	unsigned char		agent_type;
+	unsigned int		flags;
 
 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() hostid:" ZBX_FS_UI64 " itemid:" ZBX_FS_UI64 " type:%d",
 			__function_name, item->host.hostid, item->itemid, (int)item->type);
 
-	zbx_host_availability_init(&in, item->host.hostid);
-	zbx_host_availability_init(&out,item->host.hostid);
-
-	if (ZBX_AGENT_UNKNOWN == (agent_type = host_availability_agent_by_item_type(item->type)))
+	if (ZBX_AGENT_STATUS_NONE == (flags = zbx_dc_item_deactivate(item, ts, error)))
 		goto out;
 
-	if (FAIL == host_get_availability(&item->host, agent_type, &in))
+	if (HOST_AVAILABLE_UNSET == item->agent.available || HOST_AVAILABLE_UNKNOWN == item->agent.available)
 		goto out;
 
-	if (FAIL == DChost_deactivate(item->host.hostid, agent_type, ts, &in.agents[agent_type],
-			&out.agents[agent_type], error))
-	{
-		goto out;
-	}
-
-	if (FAIL == db_host_update_availability(&out))
-		goto out;
-
-	host_set_availability(&item->host, agent_type, &out);
-
-	if (0 == in.agents[agent_type].errors_from)
+	if (0 != (flags & ZBX_AGENT_STATUS_ERRORS_FROM))
 	{
 		zabbix_log(LOG_LEVEL_WARNING, "%s item \"%s\" on host \"%s\" failed:"
 				" first network error, wait for %d seconds",
 				zbx_agent_type_string(item->type), item->key_orig, item->host.host,
-				out.agents[agent_type].disable_until - ts->sec);
+				CONFIG_UNREACHABLE_DELAY);
 	}
 	else
 	{
-		if (HOST_AVAILABLE_FALSE != in.agents[agent_type].available)
+		if (HOST_AVAILABLE_FALSE != item->agent.available)
 		{
-			if (HOST_AVAILABLE_FALSE != out.agents[agent_type].available)
+			if (0 == (flags & ZBX_AGENT_STATUS_AVAILABLE))
 			{
 				zabbix_log(LOG_LEVEL_WARNING, "%s item \"%s\" on host \"%s\" failed:"
 						" another network error, wait for %d seconds",
 						zbx_agent_type_string(item->type), item->key_orig, item->host.host,
-						out.agents[agent_type].disable_until - ts->sec);
+						CONFIG_UNREACHABLE_DELAY);
 			}
 			else
 			{
@@ -324,13 +116,7 @@ void	zbx_deactivate_item_host(DC_ITEM *item, zbx_timespec_t *ts, const char *err
 			}
 		}
 	}
-
-	zabbix_log(LOG_LEVEL_DEBUG, "%s() errors_from:%d available:%d", __function_name,
-			out.agents[agent_type].errors_from, out.agents[agent_type].available);
 out:
-	zbx_host_availability_clean(&out);
-	zbx_host_availability_clean(&in);
-
 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
 }
 
@@ -746,7 +532,7 @@ static int	get_values(unsigned char poller_type, int *nextcheck)
 			case AGENT_ERROR:
 				if (HOST_AVAILABLE_TRUE != last_available)
 				{
-					zbx_activate_item_host(&items[i], &timespec);
+					zbx_activate_item_host(&items[i]);
 					last_available = HOST_AVAILABLE_TRUE;
 				}
 				break;
diff --git a/src/zabbix_server/poller/poller.h b/src/zabbix_server/poller/poller.h
index 08711ff..c1a6272 100644
--- a/src/zabbix_server/poller/poller.h
+++ b/src/zabbix_server/poller/poller.h
@@ -29,7 +29,7 @@ extern int	CONFIG_UNREACHABLE_DELAY;
 
 ZBX_THREAD_ENTRY(poller_thread, args);
 
-void	zbx_activate_item_host(DC_ITEM *item, zbx_timespec_t *ts);
+void	zbx_activate_item_host(DC_ITEM *item);
 void	zbx_deactivate_item_host(DC_ITEM *item, zbx_timespec_t *ts, const char *error);
 
 #endif
diff --git a/src/zabbix_server/server.c b/src/zabbix_server/server.c
index 593bb8b..b38c9f6 100644
--- a/src/zabbix_server/server.c
+++ b/src/zabbix_server/server.c
@@ -60,6 +60,7 @@
 #include "taskmanager/taskmanager.h"
 #include "preprocessor/preproc_manager.h"
 #include "preprocessor/preproc_worker.h"
+#include "availability/availability.h"
 #include "events.h"
 #include "../libs/zbxdbcache/valuecache.h"
 #include "setproctitle.h"
@@ -175,6 +176,7 @@ int	CONFIG_IPMIMANAGER_FORKS	= 0;
 int	CONFIG_ALERTMANAGER_FORKS	= 1;
 int	CONFIG_PREPROCMAN_FORKS		= 1;
 int	CONFIG_PREPROCESSOR_FORKS	= 3;
+int	CONFIG_AVAILABILITYSYNCER_FORKS	= 1;
 
 int	CONFIG_LISTEN_PORT		= ZBX_DEFAULT_SERVER_PORT;
 char	*CONFIG_LISTEN_IP		= NULL;
@@ -399,6 +401,11 @@ int	get_process_info_by_thread(int local_server_num, unsigned char *local_proces
 		*local_process_type = ZBX_PROCESS_TYPE_PREPROCESSOR;
 		*local_process_num = local_server_num - server_count + CONFIG_PREPROCESSOR_FORKS;
 	}
+	else if (local_server_num <= (server_count += CONFIG_AVAILABILITYSYNCER_FORKS))
+	{
+		*local_process_type = ZBX_PROCESS_TYPE_AVAILABILITY_SYNCER;
+		*local_process_num = local_server_num - server_count + CONFIG_AVAILABILITYSYNCER_FORKS;
+	}
 	else
 		return FAIL;
 
@@ -1050,7 +1057,8 @@ int	MAIN_ZABBIX_ENTRY(int flags)
 			+ CONFIG_ESCALATOR_FORKS + CONFIG_IPMIPOLLER_FORKS + CONFIG_JAVAPOLLER_FORKS
 			+ CONFIG_SNMPTRAPPER_FORKS + CONFIG_PROXYPOLLER_FORKS + CONFIG_SELFMON_FORKS
 			+ CONFIG_VMWARE_FORKS + CONFIG_TASKMANAGER_FORKS + CONFIG_IPMIMANAGER_FORKS
-			+ CONFIG_ALERTMANAGER_FORKS + CONFIG_PREPROCMAN_FORKS + CONFIG_PREPROCESSOR_FORKS;
+			+ CONFIG_ALERTMANAGER_FORKS + CONFIG_PREPROCMAN_FORKS + CONFIG_PREPROCESSOR_FORKS
+			+ CONFIG_AVAILABILITYSYNCER_FORKS;
 	threads = (pid_t *)zbx_calloc(threads, threads_num, sizeof(pid_t));
 
 	if (0 != CONFIG_TRAPPER_FORKS)
@@ -1161,6 +1169,9 @@ int	MAIN_ZABBIX_ENTRY(int flags)
 			case ZBX_PROCESS_TYPE_ALERTMANAGER:
 				threads[i] = zbx_thread_start(alert_manager_thread, &thread_args);
 				break;
+			case ZBX_PROCESS_TYPE_AVAILABILITY_SYNCER:
+				threads[i] = zbx_thread_start(availability_syncer_thread, &thread_args);
+				break;
 		}
 	}
 
diff --git a/src/zabbix_server/trapper/proxydata.c b/src/zabbix_server/trapper/proxydata.c
index 288da57..86f9280 100644
--- a/src/zabbix_server/trapper/proxydata.c
+++ b/src/zabbix_server/trapper/proxydata.c
@@ -174,8 +174,8 @@ void	zbx_send_proxy_data(zbx_socket_t *sock, zbx_timespec_t *ts)
 	struct zbx_json		j;
 	zbx_uint64_t		areg_lastid = 0, history_lastid = 0, discovery_lastid = 0;
 	char			*error = NULL;
-	int			availability_ts, more_history, more_discovery, more_areg;
-	zbx_vector_ptr_t	tasks;
+	int			more_history, more_discovery, more_areg;
+	zbx_vector_ptr_t	tasks, availability;
 	struct zbx_json_parse	jp, jp_tasks;
 
 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
@@ -186,10 +186,12 @@ void	zbx_send_proxy_data(zbx_socket_t *sock, zbx_timespec_t *ts)
 		goto out;
 	}
 
+	zbx_vector_ptr_create(&availability);
+
 	LOCK_PROXY_HISTORY;
 	zbx_json_init(&j, ZBX_JSON_STAT_BUF_LEN);
 
-	get_host_availability_data(&j, &availability_ts);
+	get_host_availability_data(&j, &availability);
 	proxy_get_hist_data(&j, &history_lastid, &more_history);
 	proxy_get_dhis_data(&j, &discovery_lastid, &more_discovery);
 	proxy_get_areg_data(&j, &areg_lastid, &more_areg);
@@ -212,8 +214,6 @@ void	zbx_send_proxy_data(zbx_socket_t *sock, zbx_timespec_t *ts)
 
 	if (SUCCEED == send_data_to_server(sock, j.buffer, &error))
 	{
-		zbx_set_availability_diff_ts(availability_ts);
-
 		DBbegin();
 
 		if (0 != history_lastid)
@@ -244,6 +244,8 @@ void	zbx_send_proxy_data(zbx_socket_t *sock, zbx_timespec_t *ts)
 	}
 	else
 	{
+		zbx_refresh_host_availability(&availability);
+
 		zabbix_log(LOG_LEVEL_WARNING, "cannot send proxy data to server at \"%s\": %s", sock->peer, error);
 		zbx_free(error);
 	}
@@ -251,6 +253,10 @@ void	zbx_send_proxy_data(zbx_socket_t *sock, zbx_timespec_t *ts)
 	zbx_vector_ptr_clear_ext(&tasks, (zbx_clean_func_t)zbx_tm_task_free);
 	zbx_vector_ptr_destroy(&tasks);
 
+	zbx_vector_ptr_clear_ext(&availability, zbx_agent_status_update_free);
+	zbx_vector_ptr_destroy(&availability);
+
+
 	zbx_json_free(&j);
 	UNLOCK_PROXY_HISTORY;
 out:
diff --git a/tests/libs/zbxhistory/Makefile.am b/tests/libs/zbxhistory/Makefile.am
index 47c6d4b..b1aa400 100644
--- a/tests/libs/zbxhistory/Makefile.am
+++ b/tests/libs/zbxhistory/Makefile.am
@@ -22,7 +22,6 @@ zbx_history_get_values_SOURCES = \
 zbx_history_get_values_WRAP = \
 	-Wl,--wrap=zbx_sleep_loop \
 	-Wl,--wrap=DCget_nextid \
-	-Wl,--wrap=zbx_host_availability_is_set \
 	-Wl,--wrap=zbx_add_event \
 	-Wl,--wrap=zbx_process_events \
 	-Wl,--wrap=zbx_clean_events
diff --git a/tests/libs/zbxhistory/zbx_history_get_values.c b/tests/libs/zbxhistory/zbx_history_get_values.c
index 0967b01..c0231fb 100644
--- a/tests/libs/zbxhistory/zbx_history_get_values.c
+++ b/tests/libs/zbxhistory/zbx_history_get_values.c
@@ -41,12 +41,6 @@ zbx_uint64_t	__wrap_DCget_nextid(const char *table_name, int num)
 	return 0;
 }
 
-int	__wrap_zbx_host_availability_is_set(const zbx_host_availability_t *ha)
-{
-	ZBX_UNUSED(ha);
-	return SUCCEED;
-}
-
 int	__wrap_zbx_add_event(unsigned char source, unsigned char object, zbx_uint64_t objectid,
 		const zbx_timespec_t *timespec, int value, const char *trigger_description,
 		const char *trigger_expression, const char *trigger_recovery_expression, unsigned char trigger_priority,
