diff --git a/include/zbxip.h b/include/zbxip.h
index 3595e66462f..e188173e23c 100644
--- a/include/zbxip.h
+++ b/include/zbxip.h
@@ -55,7 +55,7 @@ typedef struct
 	unsigned char	type;
 
 	/* 1 if the range was defined with network mask, 0 otherwise */
-	unsigned char   mask;
+	unsigned char	mask;
 }
 zbx_iprange_t;
 
diff --git a/src/libs/zbxdiscoverer/Makefile.am b/src/libs/zbxdiscoverer/Makefile.am
index 74bb27f2038..17b456f90c1 100644
--- a/src/libs/zbxdiscoverer/Makefile.am
+++ b/src/libs/zbxdiscoverer/Makefile.am
@@ -12,6 +12,8 @@ libzbxdiscoverer_a_SOURCES = \
 	discoverer_taskprep.h \
 	discoverer_async.c \
 	discoverer_async.h \
+	discoverer_snmp.c \
+	discoverer_snmp.h \
 	async_tcpsvc.c \
 	async_tcpsvc.h \
 	async_telnet.c \
diff --git a/src/libs/zbxdiscoverer/discoverer.c b/src/libs/zbxdiscoverer/discoverer.c
index e88b714e9e0..6f113ae9014 100644
--- a/src/libs/zbxdiscoverer/discoverer.c
+++ b/src/libs/zbxdiscoverer/discoverer.c
@@ -477,6 +477,23 @@ static void	process_results_incompletecheckscount_remove(zbx_discoverer_manager_
 	}
 }
 
+static int	process_results_drule_is_lastip(zbx_discoverer_results_t *result, zbx_vector_uint64_t *del_jobs)
+{
+	if (ZBX_DISCOVERER_RESULT_CHECK_INIT == result->status ||
+			0 != (result->status & ZBX_DISCOVERER_RESULT_JOB_FINISH))
+	{
+		return FAIL;
+	}
+
+	if (0 == del_jobs->values_num)
+		return SUCCEED;
+
+	if (FAIL != zbx_vector_uint64_bsearch(del_jobs, result->druleid, ZBX_DEFAULT_UINT64_COMPARE_FUNC))
+		result->status |= ZBX_DISCOVERER_RESULT_JOB_FINISH;
+
+	return 0 != (result->status & ZBX_DISCOVERER_RESULT_JOB_FINISH) ? FAIL : SUCCEED;
+}
+
 static void	process_results_incompleteresult_remove(zbx_discoverer_manager_t *manager,
 		zbx_vector_discoverer_drule_error_t *drule_errors)
 {
@@ -510,7 +527,7 @@ static void	process_results_incompleteresult_remove(zbx_discoverer_manager_t *ma
 }
 
 static int	process_results(zbx_discoverer_manager_t *manager, zbx_vector_uint64_t *del_druleids,
-		zbx_hashset_t *incomplete_druleids, zbx_uint64_t *unsaved_checks,
+		zbx_vector_uint64_t *del_jobs, zbx_hashset_t *incomplete_druleids, zbx_uint64_t *unsaved_checks,
 		zbx_vector_discoverer_drule_error_t *drule_errors, const zbx_events_funcs_t *events_cbs,
 		zbx_discovery_open_func_t discovery_open_cb, zbx_discovery_close_func_t discovery_close_cb,
 		zbx_discovery_update_host_func_t discovery_update_host_cb,
@@ -520,13 +537,14 @@ static int	process_results(zbx_discoverer_manager_t *manager, zbx_vector_uint64_
 {
 #define DISCOVERER_BATCH_RESULTS_NUM	1000
 	zbx_uint64_t				res_check_total = 0,res_check_count = 0;
-	zbx_vector_discoverer_results_ptr_t	results;
+	zbx_vector_discoverer_results_ptr_t	results, results_lastip;
 	zbx_discoverer_results_t		*result, *result_tmp;
 	zbx_hashset_iter_t			iter;
 
 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() del_druleids:%d", __func__, del_druleids->values_num);
 
 	zbx_vector_discoverer_results_ptr_create(&results);
+	zbx_vector_discoverer_results_ptr_create(&results_lastip);
 	zbx_hashset_clear(incomplete_druleids);
 
 	pthread_mutex_lock(&manager->results_lock);
@@ -552,7 +570,8 @@ static int	process_results(zbx_discoverer_manager_t *manager, zbx_vector_uint64_
 
 		res_check_total += (zbx_uint64_t)result->services.values_num;
 
-		if (DISCOVERER_BATCH_RESULTS_NUM <= res_check_count ||
+		if (SUCCEED == process_results_drule_is_lastip(result, del_jobs) ||
+				DISCOVERER_BATCH_RESULTS_NUM <= res_check_count ||
 				(NULL != (check_count = zbx_hashset_search(&manager->incomplete_checks_count, &cmp)) &&
 				0 != check_count->count))
 		{
@@ -567,7 +586,12 @@ static int	process_results(zbx_discoverer_manager_t *manager, zbx_vector_uint64_
 
 		result_tmp = (zbx_discoverer_results_t*)zbx_malloc(NULL, sizeof(zbx_discoverer_results_t));
 		memcpy(result_tmp, result, sizeof(zbx_discoverer_results_t));
-		zbx_vector_discoverer_results_ptr_append(&results, result_tmp);
+
+		if (0 != (result_tmp->status & ZBX_DISCOVERER_RESULT_CHECK_LAST))
+			zbx_vector_discoverer_results_ptr_append(&results_lastip, result_tmp);
+		else
+			zbx_vector_discoverer_results_ptr_append(&results, result_tmp);
+
 		zbx_hashset_iter_remove(&iter);
 	}
 
@@ -579,6 +603,10 @@ static int	process_results(zbx_discoverer_manager_t *manager, zbx_vector_uint64_
 
 	pthread_mutex_unlock(&manager->results_lock);
 
+	zbx_vector_discoverer_results_ptr_append_array(&results, results_lastip.values, results_lastip.values_num);
+	zbx_vector_discoverer_results_ptr_clear(&results_lastip);
+
+
 	if (0 != results.values_num)
 	{
 		void	*handle = discovery_open_cb();
@@ -626,6 +654,7 @@ static int	process_results(zbx_discoverer_manager_t *manager, zbx_vector_uint64_
 
 	zbx_vector_discoverer_results_ptr_clear_ext(&results, results_free);
 	zbx_vector_discoverer_results_ptr_destroy(&results);
+	zbx_vector_discoverer_results_ptr_destroy(&results_lastip);
 
 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() ret:%d", __func__,
 			DISCOVERER_BATCH_RESULTS_NUM <= res_check_count ? 1 : 0);
@@ -646,10 +675,6 @@ static void	process_job_finalize(zbx_vector_uint64_t *del_jobs, zbx_vector_disco
 	if (0 == del_jobs->values_num)
 		return;
 
-	/* multiple errors can duplicate druleid */
-	zbx_vector_uint64_sort(del_jobs, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
-	zbx_vector_uint64_uniq(del_jobs, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
-
 	now = time(NULL);
 	handle = discovery_open_cb();
 
@@ -884,7 +909,7 @@ zbx_discoverer_dservice_t	*result_dservice_create(const unsigned short port,
 	return service;
 }
 
-zbx_discoverer_results_t	*discoverer_result_create(zbx_uint64_t druleid, const zbx_uint64_t unique_dcheckid)
+zbx_discoverer_results_t	*discoverer_result_create(zbx_uint64_t druleid, const zbx_discoverer_task_t *task)
 {
 	zbx_discoverer_results_t	*result;
 
@@ -893,16 +918,18 @@ zbx_discoverer_results_t	*discoverer_result_create(zbx_uint64_t druleid, const z
 	zbx_vector_discoverer_services_ptr_create(&result->services);
 
 	result->druleid = druleid;
-	result->unique_dcheckid = unique_dcheckid;
+	result->unique_dcheckid = task->unique_dcheckid;
 	result->ip = result->dnsname = NULL;
 	result->now = time(NULL);
 	result->processed_checks_per_ip = 0;
-
+	result->max_checks_per_ip = task->range.state.checks_per_ip;
+	result->status = (SUCCEED == discoverer_task_is_lastip(task) ?
+			ZBX_DISCOVERER_RESULT_CHECK_LAST : ZBX_DISCOVERER_RESULT_CHECK_INIT);
 	return result;
 }
 
 static zbx_discoverer_results_t	*discoverer_results_host_reg(zbx_hashset_t *hr_dst, zbx_uint64_t druleid,
-		zbx_uint64_t unique_dcheckid, char *ip)
+		zbx_uint64_t unique_dcheckid, char *ip, int last_ip)
 {
 	zbx_discoverer_results_t	*dst, src = {.druleid = druleid, .ip = ip};
 
@@ -915,6 +942,9 @@ static zbx_discoverer_results_t	*discoverer_results_host_reg(zbx_hashset_t *hr_d
 		dst->now = time(NULL);
 		dst->unique_dcheckid = unique_dcheckid;
 		dst->dnsname = zbx_strdup(NULL, "");
+		dst->status = (SUCCEED == last_ip ?
+				ZBX_DISCOVERER_RESULT_CHECK_LAST : ZBX_DISCOVERER_RESULT_CHECK_INIT);
+		dst->processed_checks_per_ip = dst->max_checks_per_ip = 0;
 	}
 
 	return dst;
@@ -925,7 +955,7 @@ ZBX_PTR_VECTOR_IMPL(fping_host, zbx_fping_host_t)
 
 static int	discoverer_icmp_result_merge(zbx_hashset_t *incomplete_checks_count, zbx_hashset_t *results,
 		const zbx_uint64_t druleid, const zbx_uint64_t dcheckid, const zbx_uint64_t unique_dcheckid,
-		const zbx_vector_fping_host_t *hosts)
+		const zbx_vector_fping_host_t *hosts, int is_lastip)
 {
 	int	i;
 
@@ -944,7 +974,8 @@ static int	discoverer_icmp_result_merge(zbx_hashset_t *incomplete_checks_count,
 		}
 
 		/* we must register at least 1 empty result per ip */
-		result = discoverer_results_host_reg(results, druleid, unique_dcheckid, ip);
+		result = discoverer_results_host_reg(results, druleid, unique_dcheckid, ip,
+				SUCCEED == is_lastip && 0 == hosts->values_num - i + 1 ? SUCCEED : FAIL);
 
 		if (0 == h->rcv)
 			continue;
@@ -1011,7 +1042,8 @@ static int	discoverer_icmp(const zbx_uint64_t druleid, zbx_discoverer_task_t *ta
 		{
 			pthread_mutex_lock(&dmanager.results_lock);
 			abort = discoverer_icmp_result_merge(&dmanager.incomplete_checks_count, &dmanager.results,
-					druleid, dcheck->dcheckid, task->unique_dcheckid, &hosts);
+					druleid, dcheck->dcheckid, task->unique_dcheckid, &hosts,
+					discoverer_task_check_count_get(task));
 			pthread_mutex_unlock(&dmanager.results_lock);
 		}
 
@@ -1042,7 +1074,8 @@ static int	discoverer_icmp(const zbx_uint64_t druleid, zbx_discoverer_task_t *ta
 		{
 			pthread_mutex_lock(&dmanager.results_lock);
 			(void)discoverer_icmp_result_merge(&dmanager.incomplete_checks_count, &dmanager.results,
-					druleid, dcheck->dcheckid, task->unique_dcheckid, &hosts);
+					druleid, dcheck->dcheckid, task->unique_dcheckid, &hosts,
+					discoverer_task_check_count_get(task));
 			pthread_mutex_unlock(&dmanager.results_lock);
 		}
 	}
@@ -1084,17 +1117,17 @@ static void	discoverer_results_move_value(zbx_discoverer_results_t *src, zbx_has
 		src->dnsname = NULL;
 	}
 
+	dst->status |= src->status;
+
 	zbx_vector_discoverer_services_ptr_append_array(&dst->services, src->services.values,
 			src->services.values_num);
 	zbx_vector_discoverer_services_ptr_clear(&src->services);
 	results_free(src);
 }
 
-int	discoverer_results_partrange_merge(zbx_hashset_t *hr_dst, zbx_vector_discoverer_results_ptr_t *vr_src,
-		zbx_discoverer_task_t *task, int force)
+int	discoverer_results_partrange_merge(zbx_hashset_t *hr_dst, zbx_vector_discoverer_results_ptr_t *vr_src,int force)
 {
-	int		i, ret = SUCCEED;
-	zbx_uint64_t	druleid = task->ds_dchecks.values[0]->dcheck.druleid;
+	int	i, ret = SUCCEED;
 
 	zabbix_log(LOG_LEVEL_DEBUG, "[%d] In %s() src:%d dst:%d", log_worker_id, __func__, vr_src->values_num,
 			hr_dst->num_data);
@@ -1103,17 +1136,17 @@ int	discoverer_results_partrange_merge(zbx_hashset_t *hr_dst, zbx_vector_discove
 	{
 		zbx_discoverer_results_t	*src = vr_src->values[0];
 
-		ret = discoverer_drule_check(&dmanager.incomplete_checks_count, druleid, src->ip);
+		ret = discoverer_drule_check(&dmanager.incomplete_checks_count, src->druleid, src->ip);
 	}
 
 	for (i = vr_src->values_num - 1; i >= 0 && SUCCEED == ret; i--)
 	{
 		zbx_discoverer_results_t	*src = vr_src->values[i];
 
-		if (0 == force && src->processed_checks_per_ip != task->range.state.checks_per_ip)
+		if (0 == force && src->processed_checks_per_ip != src->max_checks_per_ip)
 			continue;
 
-		if (FAIL == (ret = discoverer_check_count_decrease(&dmanager.incomplete_checks_count, druleid,
+		if (FAIL == (ret = discoverer_check_count_decrease(&dmanager.incomplete_checks_count, src->druleid,
 				src->ip, src->processed_checks_per_ip)))
 		{
 			break;	/* config revision id was changed */
@@ -1180,7 +1213,8 @@ static int	discoverer_net_check_common(zbx_uint64_t druleid, zbx_discoverer_task
 	if (SUCCEED == discoverer_check_count_decrease(&dmanager.incomplete_checks_count, druleid, ip, 1))
 	{
 		/* we must register at least 1 empty result per ip */
-		result = discoverer_results_host_reg(&dmanager.results, druleid, task->unique_dcheckid, ip);
+		result = discoverer_results_host_reg(&dmanager.results, druleid, task->unique_dcheckid, ip,
+				discoverer_task_is_lastip(task));
 
 		if (NULL != service)
 		{
@@ -1306,16 +1340,23 @@ static void	*discoverer_worker_entry(void *net_check_worker)
 			/* process checks */
 
 			zbx_timekeeper_update(worker->timekeeper, worker->worker_id - 1, ZBX_PROCESS_STATE_BUSY);
+			dcheck_type = GET_DTYPE(task);
 
 			if (FAIL == dcheck_is_async(task->ds_dchecks.values[0]))
 			{
 				ret = discoverer_net_check_common(druleid, task, &error);
 			}
-			else if (SVC_ICMPPING == GET_DTYPE(task))
+			else if (SVC_ICMPPING == dcheck_type)
 			{
 				ret = discoverer_net_check_icmp(druleid, task, concurrency_max, &worker->stop, queue,
 						&error);
 			}
+			else if (SVC_SNMPv3 == dcheck_type || SVC_SNMPv2c == dcheck_type || SVC_SNMPv1 == dcheck_type)
+			{
+				ret = discovery_jobs_check_snmp(druleid, task, concurrency_max, &worker->stop,
+						&dmanager, log_worker_id, &error);
+
+			}
 			else
 			{
 				ret = discovery_net_check_range(druleid, task, concurrency_max, &worker->stop,
@@ -1328,7 +1369,6 @@ static void	*discoverer_worker_entry(void *net_check_worker)
 						worker->worker_id, druleid, ZBX_NULL2STR(error));
 			}
 
-			dcheck_type = GET_DTYPE(task);
 			discoverer_task_free(task);
 			zbx_timekeeper_update(worker->timekeeper, worker->worker_id - 1, ZBX_PROCESS_STATE_IDLE);
 
@@ -1755,10 +1795,14 @@ ZBX_THREAD_ENTRY(zbx_discoverer_thread, args)
 		discoverer_queue_unlock(&dmanager.queue);
 
 		zbx_vector_uint64_sort(&del_druleids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
+		/* multiple errors can duplicate druleid */
+		zbx_vector_uint64_sort(&del_jobs, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
+		zbx_vector_uint64_uniq(&del_jobs, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
 
-		more_results = process_results(&dmanager, &del_druleids, &incomplete_druleids, &unsaved_checks,
-				&drule_errors, discoverer_args_in->events_cbs, discoverer_args_in->discovery_open_cb,
-				discoverer_args_in->discovery_close_cb, discoverer_args_in->discovery_update_host_cb,
+		more_results = process_results(&dmanager, &del_druleids, &del_jobs, &incomplete_druleids,
+				&unsaved_checks, &drule_errors, discoverer_args_in->events_cbs,
+				discoverer_args_in->discovery_open_cb, discoverer_args_in->discovery_close_cb,
+				discoverer_args_in->discovery_update_host_cb,
 				discoverer_args_in->discovery_update_service_cb,
 				discoverer_args_in->discovery_update_service_down_cb,
 				discoverer_args_in->discovery_find_host_cb);
@@ -1886,7 +1930,9 @@ ZBX_THREAD_ENTRY(zbx_discoverer_thread, args)
 	discoverer_manager_free(&dmanager);
 	zbx_ipc_service_close(&ipc_service);
 	zbx_db_close();
-
+#if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
+	zbx_tls_free();
+#endif
 	zbx_setproctitle("%s #%d [terminated]", get_process_type_string(info->process_type), info->process_num);
 
 	exit(EXIT_SUCCESS);
diff --git a/src/libs/zbxdiscoverer/discoverer_async.c b/src/libs/zbxdiscoverer/discoverer_async.c
index e875217aa26..2d792cd57b4 100644
--- a/src/libs/zbxdiscoverer/discoverer_async.c
+++ b/src/libs/zbxdiscoverer/discoverer_async.c
@@ -73,7 +73,7 @@ static int	discovery_async_poller_dns_init(discovery_poller_config_t *poller_con
 	return SUCCEED;
 }
 
-static void	discovery_async_poller_destroy(discovery_poller_config_t *poller_config)
+void	discovery_async_poller_destroy(discovery_poller_config_t *poller_config)
 {
 	zabbix_log(LOG_LEVEL_DEBUG, "[%d] In %s()", log_worker_id, __func__);
 
@@ -83,7 +83,7 @@ static void	discovery_async_poller_destroy(discovery_poller_config_t *poller_con
 	zabbix_log(LOG_LEVEL_DEBUG, "[%d] End of %s()", log_worker_id, __func__);
 }
 
-static int	discovery_async_poller_init(zbx_discoverer_manager_t *dmanager,
+int	discovery_async_poller_init(zbx_discoverer_manager_t *dmanager,
 		discovery_poller_config_t *poller_config)
 {
 	int	ret;
@@ -110,132 +110,6 @@ out:
 	return ret;
 }
 
-#ifdef HAVE_NETSNMP
-static void	process_snmp_result(void *data)
-{
-	discovery_async_result_t	*async_result = zbx_async_check_snmp_get_arg(data);
-	zbx_dc_item_context_t	*item = zbx_async_check_snmp_get_item_context(data);
-	char			**pvalue;
-
-	zabbix_log(LOG_LEVEL_DEBUG, "[%d] In %s() key:'%s' host:'%s' addr:'%s' ret:%s", log_worker_id, __func__,
-			item->key, item->host, item->interface.addr, zbx_result_string(item->ret));
-
-	async_result->poller_config->processing--;
-	async_result->dresult->processed_checks_per_ip++;
-
-	if (SUCCEED == item->ret && NULL != (pvalue = ZBX_GET_TEXT_RESULT(&item->result)))
-	{
-		zbx_discoverer_dservice_t	*service;
-
-		service = result_dservice_create(item->interface.port, async_result->dcheckid);
-		zbx_strlcpy_utf8(service->value, *pvalue, ZBX_MAX_DISCOVERED_VALUE_SIZE);
-		service->status = DOBJECT_STATUS_UP;
-		zbx_vector_discoverer_services_ptr_append(&async_result->dresult->services, service);
-
-		if (NULL ==  async_result->dresult->dnsname || '\0' == *async_result->dresult->dnsname)
-		{
-			const char	*rdns = ZBX_NULL2EMPTY_STR(zbx_async_check_snmp_get_reverse_dns(data));
-
-			if ('\0' != *rdns && SUCCEED != zbx_validate_hostname(rdns))
-				rdns = "";
-
-			async_result->dresult->dnsname = zbx_strdup(async_result->dresult->dnsname, rdns);
-		}
-	}
-
-	zbx_free(async_result);
-	zbx_async_check_snmp_clean(data);
-
-	zabbix_log(LOG_LEVEL_DEBUG, "[%d] End of %s()", log_worker_id, __func__);
-}
-
-static int	discovery_snmp(discovery_poller_config_t *poller_config, const zbx_dc_dcheck_t *dcheck,
-		char *ip, const unsigned short port, zbx_discoverer_results_t *dresult, char **error)
-{
-	int				ret;
-	zbx_dc_item_t			item;
-	AGENT_RESULT			result;
-	discovery_async_result_t	*async_result;
-
-	async_result = (discovery_async_result_t *) zbx_malloc(NULL, sizeof(discovery_async_result_t));
-	async_result->dresult = dresult;
-	async_result->poller_config = poller_config;
-	async_result->dcheckid = dcheck->dcheckid;
-
-	zbx_init_agent_result(&result);
-
-	memset(&item, 0, sizeof(zbx_dc_item_t));
-	zbx_strscpy(item.key_orig, dcheck->key_);
-	item.key = item.key_orig;
-
-	item.interface.useip = 1;
-	zbx_strscpy(item.interface.ip_orig, ip);
-	item.interface.addr = item.interface.ip_orig;
-	item.interface.port = port;
-
-	item.value_type = ITEM_VALUE_TYPE_STR;
-
-	switch (dcheck->type)
-	{
-		case SVC_SNMPv1:
-			item.snmp_version = ZBX_IF_SNMP_VERSION_1;
-			item.type = ITEM_TYPE_SNMP;
-			break;
-		case SVC_SNMPv2c:
-			item.snmp_version = ZBX_IF_SNMP_VERSION_2;
-			item.type = ITEM_TYPE_SNMP;
-			break;
-		case SVC_SNMPv3:
-			item.snmp_version = ZBX_IF_SNMP_VERSION_3;
-			item.type = ITEM_TYPE_SNMP;
-	}
-
-	item.snmp_community = zbx_strdup(NULL, dcheck->snmp_community);
-	item.snmp_oid = dcheck->key_;
-	item.timeout = dcheck->timeout;
-
-	if (ZBX_IF_SNMP_VERSION_3 == item.snmp_version)
-	{
-		item.snmpv3_securityname = zbx_strdup(NULL, dcheck->snmpv3_securityname);
-		item.snmpv3_authpassphrase = zbx_strdup(NULL, dcheck->snmpv3_authpassphrase);
-		item.snmpv3_privpassphrase = zbx_strdup(NULL, dcheck->snmpv3_privpassphrase);
-
-		item.snmpv3_contextname = zbx_strdup(NULL, dcheck->snmpv3_contextname);
-
-		item.snmpv3_securitylevel = dcheck->snmpv3_securitylevel;
-		item.snmpv3_authprotocol = dcheck->snmpv3_authprotocol;
-		item.snmpv3_privprotocol = dcheck->snmpv3_privprotocol;
-	}
-
-	zbx_set_snmp_bulkwalk_options(poller_config->progname);
-
-	if (SUCCEED != (ret = zbx_async_check_snmp(&item, &result, process_snmp_result, async_result, NULL,
-			poller_config->base, NULL, poller_config->dnsbase, poller_config->config_source_ip,
-			ZABBIX_ASYNC_RESOLVE_REVERSE_DNS_YES, 0)))
-	{
-		if (ZBX_ISSET_MSG(&result))
-			*error = zbx_strdup(*error, *ZBX_GET_MSG_RESULT(&result));
-		else
-			*error = zbx_strdup(*error, "Error of snmp check");
-
-		zbx_free(async_result);
-	}
-	else
-		poller_config->processing++;
-
-	zbx_free(item.snmp_community);
-	zbx_free(item.snmpv3_securityname);
-	zbx_free(item.snmpv3_authpassphrase);
-	zbx_free(item.snmpv3_privpassphrase);
-	zbx_free(item.snmpv3_contextname);
-	zbx_free_agent_result(&result);
-
-	zabbix_log(LOG_LEVEL_DEBUG, "[%d] %s() ip:%s port:%d, key:%s ret:%d", log_worker_id, __func__,
-			ip, port, item.key_orig, ret);
-	return ret;
-}
-#endif
-
 static void	process_agent_result(void *data)
 {
 	zbx_agent_context		*agent_context = (zbx_agent_context *)data;
@@ -583,7 +457,7 @@ static int	discovery_http(discovery_poller_config_t *poller_config, zbx_asynchtt
 }
 #endif
 
-static int	discovery_net_check_result_flush(zbx_discoverer_manager_t *dmanager, zbx_discoverer_task_t *task,
+int	discovery_net_check_result_flush(zbx_discoverer_manager_t *dmanager,
 		zbx_vector_discoverer_results_ptr_t *results, int force)
 {
 	static ZBX_THREAD_LOCAL time_t	last;
@@ -594,7 +468,7 @@ static int	discovery_net_check_result_flush(zbx_discoverer_manager_t *dmanager,
 		return ret;
 
 	pthread_mutex_lock(&dmanager->results_lock);
-	ret = discoverer_results_partrange_merge(&dmanager->results, results, task, force);
+	ret = discoverer_results_partrange_merge(&dmanager->results, results, force);
 	pthread_mutex_unlock(&dmanager->results_lock);
 
 	zabbix_log(LOG_LEVEL_DEBUG, "[%d] %s() results:%d saved:%d ret:%d", log_worker_id, __func__,
@@ -639,12 +513,13 @@ int	discovery_net_check_range(zbx_uint64_t druleid, zbx_discoverer_task_t *task,
 			ZBX_FS_UI64 " checks per ip:%u dchecks:%d type:%u concurrency_max:%d checks_per_worker_max:%d",
 			log_worker_id, __func__, druleid, task->range.id, task->range.state.count,
 			task->range.state.checks_per_ip, task->ds_dchecks.values_num,
-			task->ds_dchecks.values[task->range.state.index_dcheck]->dcheck.type, concurrency_max,
-			dmanager->queue.checks_per_worker_max);
+			GET_DTYPE(task), concurrency_max, dmanager->queue.checks_per_worker_max);
 
 	if (0 == concurrency_max)
 		concurrency_max = dmanager->queue.checks_per_worker_max;
 
+	*first_ip = *ip = '\0';
+
 	if (SUCCEED != discovery_async_poller_init(dmanager, &poller_config))
 	{
 		*error = zbx_strdup(*error, "Cannot initialize discovery async poller.");
@@ -652,7 +527,6 @@ int	discovery_net_check_range(zbx_uint64_t druleid, zbx_discoverer_task_t *task,
 	}
 
 	zbx_vector_discoverer_results_ptr_create(&results);
-	*first_ip = '\0';
 #ifdef HAVE_LIBCURL
 	if ((SVC_HTTP == GET_DTYPE(task) || SVC_HTTPS == GET_DTYPE(task)) &&
 			NULL == (http_config = zbx_async_httpagent_create(poller_config.base, process_http_response,
@@ -671,24 +545,13 @@ int	discovery_net_check_range(zbx_uint64_t druleid, zbx_discoverer_task_t *task,
 		if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_DEBUG) && '\0' == *first_ip)
 			zbx_strlcpy(first_ip, ip, sizeof(first_ip));
 
-		result = discoverer_result_create(druleid, task->unique_dcheckid);
+		result = discoverer_result_create(druleid, task);
 		result->ip = zbx_strdup(NULL, ip);
 		zbx_vector_discoverer_results_ptr_append(&results, result);
 		dcheck = &task->ds_dchecks.values[task->range.state.index_dcheck]->dcheck;
 
 		switch (dcheck->type)
 		{
-			case SVC_SNMPv1:
-			case SVC_SNMPv2c:
-			case SVC_SNMPv3:
-#ifdef HAVE_NETSNMP
-				ret = discovery_snmp(&poller_config, dcheck, ip,
-						(unsigned short)task->range.state.port, result, error);
-#else
-				ret = FAIL;
-				*error = zbx_strdup(*error, "Support for SNMP checks was not compiled in.");
-#endif
-				break;
 			case SVC_AGENT:
 				ret = discovery_agent(&poller_config, dcheck, ip,
 						(unsigned short)task->range.state.port, result, error);
@@ -730,7 +593,7 @@ int	discovery_net_check_range(zbx_uint64_t druleid, zbx_discoverer_task_t *task,
 		while (concurrency_max == poller_config.processing)
 			event_base_loop(poller_config.base, EVLOOP_ONCE);
 
-		abort = discovery_net_check_result_flush(dmanager, task, &results, 0);
+		abort = discovery_net_check_result_flush(dmanager, &results, 0);
 
 		if (SUCCEED == discovery_pending_checks_count_decrease(&dmanager->queue, concurrency_max,
 				task->range.state.count, ++dec_counter))
@@ -743,10 +606,10 @@ out:
 	while (0 != poller_config.processing)	/* try to close all handles if they are exhausted */
 	{
 		event_base_loop(poller_config.base, EVLOOP_ONCE);
-		discovery_net_check_result_flush(dmanager, task, &results, 0);
+		discovery_net_check_result_flush(dmanager, &results, 0);
 	}
 
-	discovery_net_check_result_flush(dmanager, task, &results, 1);
+	discovery_net_check_result_flush(dmanager, &results, 1);
 	zbx_vector_discoverer_results_ptr_clear_ext(&results, results_free);	/* Incomplete results*/
 	zbx_vector_discoverer_results_ptr_destroy(&results);
 #ifdef HAVE_LIBCURL
diff --git a/src/libs/zbxdiscoverer/discoverer_async.h b/src/libs/zbxdiscoverer/discoverer_async.h
index 8af9ff6ab45..e3a9bfc3305 100644
--- a/src/libs/zbxdiscoverer/discoverer_async.h
+++ b/src/libs/zbxdiscoverer/discoverer_async.h
@@ -18,6 +18,7 @@
 #include <event2/dns.h>
 #include "discoverer_int.h"
 #include "discoverer_job.h"
+#include "discoverer_snmp.h"
 
 typedef struct
 {
@@ -39,9 +40,13 @@ typedef struct
 discovery_async_result_t;
 
 void	process_http_result(void *data);
+int	discovery_async_poller_init(zbx_discoverer_manager_t *dmanager, discovery_poller_config_t *poller_config);
 int	discovery_net_check_range(zbx_uint64_t druleid, zbx_discoverer_task_t *task, int worker_max, int *stop,
 		zbx_discoverer_manager_t *dmanager, int worker_id, char **error);
 int	discovery_pending_checks_count_decrease(zbx_discoverer_queue_t *queue, int worker_max,
 		zbx_uint64_t total, zbx_uint64_t dec_counter);
+int	discovery_net_check_result_flush(zbx_discoverer_manager_t *dmanager,
+		zbx_vector_discoverer_results_ptr_t *results, int force);
+void	discovery_async_poller_destroy(discovery_poller_config_t *poller_config);
 
 #endif /* ZABBIX_DISCOVERER_ASYNC_H */
diff --git a/src/libs/zbxdiscoverer/discoverer_int.h b/src/libs/zbxdiscoverer/discoverer_int.h
index 212b1a935de..a7fc81ce783 100644
--- a/src/libs/zbxdiscoverer/discoverer_int.h
+++ b/src/libs/zbxdiscoverer/discoverer_int.h
@@ -19,12 +19,15 @@
 #include "zbxtimekeeper.h"
 
 #define DISCOVERER_JOB_TASKS_INPROGRESS_MAX	1000
+#define DISCOVERER_SNMP_CHECKS_INPROGRESS_MAX	10000
 
 #define DISCOVERER_WORKER_INIT_NONE	0x00
 #define DISCOVERER_WORKER_INIT_THREAD	0x01
 
 #define GET_DTYPE(t)		t->ds_dchecks.values[0]->dcheck.type
-#define TASK_IP2STR(t, ip_str)	zbx_iprange_ip2str(t->range.ipranges->values[t->range.state.index_ip].type, \
+#define GET_DRULEID(t)		t->ds_dchecks.values[0]->dcheck.druleid
+#define GET_DCHECKID(t)		t->ds_dchecks.values[0]->dcheck.dcheckid
+#define TASK_IP2STR(t, ip_str)	zbx_iprange_ip2str(t->range.ipranges->values[0].type, \
 					t->range.state.ipaddress, ip_str, sizeof(ip_str))
 
 typedef struct
@@ -85,15 +88,19 @@ typedef struct
 	time_t					now;
 	zbx_uint64_t				unique_dcheckid;
 	unsigned int				processed_checks_per_ip;
+	unsigned int				max_checks_per_ip;
+#	define ZBX_DISCOVERER_RESULT_CHECK_INIT	0x00
+#	define ZBX_DISCOVERER_RESULT_CHECK_LAST	0x01
+#	define ZBX_DISCOVERER_RESULT_JOB_FINISH	0x02
+	unsigned char				status;
 }
 zbx_discoverer_results_t;
 
 ZBX_PTR_VECTOR_DECL(discoverer_results_ptr, zbx_discoverer_results_t*)
 
-zbx_discoverer_results_t	*discoverer_result_create(zbx_uint64_t druleid, const zbx_uint64_t unique_dcheckid);
+zbx_discoverer_results_t	*discoverer_result_create(zbx_uint64_t druleid, const zbx_discoverer_task_t *task);
 int				discoverer_results_partrange_merge(zbx_hashset_t *hr_dst,
-					zbx_vector_discoverer_results_ptr_t *vr_src, zbx_discoverer_task_t *task,
-					int force);
+					zbx_vector_discoverer_results_ptr_t *vr_src, int force);
 void				results_free(zbx_discoverer_results_t *result);
 zbx_discoverer_dservice_t	*result_dservice_create(const unsigned short port, const zbx_uint64_t dcheckid);
 void				dcheck_port_ranges_get(const char *ports, zbx_vector_portrange_t *ranges);
diff --git a/src/libs/zbxdiscoverer/discoverer_job.c b/src/libs/zbxdiscoverer/discoverer_job.c
index a485e59a73b..5e749e065ae 100644
--- a/src/libs/zbxdiscoverer/discoverer_job.c
+++ b/src/libs/zbxdiscoverer/discoverer_job.c
@@ -21,7 +21,7 @@ ZBX_VECTOR_IMPL(iprange, zbx_iprange_t)
 
 int	discoverer_range_check_iter(zbx_discoverer_task_t *task)
 {
-	int			ret;
+	int		ret;
 	zbx_ds_dcheck_t	*dcheck = task->ds_dchecks.values[task->range.state.index_dcheck];
 
 	if (0 == task->range.state.count)
@@ -93,11 +93,19 @@ void	discoverer_task_free(zbx_discoverer_task_t *task)
 	zbx_free(task);
 }
 
-zbx_uint64_t	discoverer_task_check_count_get(zbx_discoverer_task_t *task)
+zbx_uint64_t	discoverer_task_check_count_get(const zbx_discoverer_task_t *task)
 {
 	return task->range.state.count;
 }
 
+int	discoverer_task_is_lastip(const zbx_discoverer_task_t *task)
+{
+	zbx_task_range_t	range = {.state = task->range.state};
+
+	return FAIL == zbx_iprange_uniq_iter(task->range.ipranges->values, task->range.ipranges->values_num,
+			&range.state.index_ip, range.state.ipaddress) ? SUCCEED : FAIL;
+}
+
 static zbx_discoverer_task_t	*discoverer_task_clone(zbx_discoverer_task_t *task)
 {
 	zbx_discoverer_task_t	*task_copy;
@@ -259,3 +267,4 @@ void	discoverer_job_abort(zbx_discoverer_job_t *job, zbx_uint64_t *pending_check
 	discoverer_queue_append_error(errors, job->druleid, error);
 	*pending_checks_count -= discoverer_job_tasks_free(job);
 }
+
diff --git a/src/libs/zbxdiscoverer/discoverer_job.h b/src/libs/zbxdiscoverer/discoverer_job.h
index 9c5ceb94529..98dec26a4a0 100644
--- a/src/libs/zbxdiscoverer/discoverer_job.h
+++ b/src/libs/zbxdiscoverer/discoverer_job.h
@@ -81,8 +81,8 @@ zbx_hash_t		discoverer_task_hash(const void *data);
 int			discoverer_task_compare(const void *d1, const void *d2);
 void			discoverer_task_clear(zbx_discoverer_task_t *task);
 void			discoverer_task_free(zbx_discoverer_task_t *task);
-zbx_uint64_t		discoverer_task_check_count_get(zbx_discoverer_task_t *task);
-zbx_uint64_t		discoverer_task_ip_check_count_get(zbx_discoverer_task_t *task);
+zbx_uint64_t		discoverer_task_check_count_get(const zbx_discoverer_task_t *task);
+int			discoverer_task_is_lastip(const zbx_discoverer_task_t *task);
 zbx_uint64_t		discoverer_job_tasks_free(zbx_discoverer_job_t *job);
 void			discoverer_job_free(zbx_discoverer_job_t *job);
 zbx_discoverer_job_t	*discoverer_job_create(zbx_dc_drule_t *drule, zbx_vector_ds_dcheck_ptr_t *ds_dchecks_common,
diff --git a/src/libs/zbxdiscoverer/discoverer_queue.c b/src/libs/zbxdiscoverer/discoverer_queue.c
index 98fadb35108..5781a11c80c 100644
--- a/src/libs/zbxdiscoverer/discoverer_queue.c
+++ b/src/libs/zbxdiscoverer/discoverer_queue.c
@@ -98,12 +98,12 @@ zbx_discoverer_job_t	*discoverer_queue_pop(zbx_discoverer_queue_t *queue)
 
 	zbx_vector_uint64_create(&ids);
 
-	while (SUCCEED == zbx_list_pop(&queue->jobs, (void*)&job))
+	while (SUCCEED == zbx_list_pop(&queue->jobs, (void**)&job))
 	{
 		int		one_task = SUCCEED;
 		zbx_uint64_t	id;
 
-		if (SUCCEED != zbx_list_peek(&job->tasks, (void*)&task))
+		if (SUCCEED != zbx_list_peek(&job->tasks, (void**)&task))
 			break;
 
 		if (SVC_SNMPv3 != GET_DTYPE(task) && SVC_SNMPv2c != GET_DTYPE(task) && SVC_SNMPv1 != GET_DTYPE(task))
@@ -115,11 +115,11 @@ zbx_discoverer_job_t	*discoverer_queue_pop(zbx_discoverer_queue_t *queue)
 			break;
 		}
 
-		id = task->ds_dchecks.values[0]->dcheck.dcheckid;
+		id = GET_DCHECKID(task);
 
 		if (job->tasks.head != job->tasks.tail)				/* if not one snmp task in the list */
 		{
-			(void)zbx_list_pop(&job->tasks, (void*)&task);
+			(void)zbx_list_pop(&job->tasks, (void**)&task);
 			(void)zbx_list_append(&job->tasks, (void*)task, NULL);	/* put task to end of the list */
 			one_task = FAIL;
 		}
@@ -302,3 +302,84 @@ void	discoverer_queue_append_error(zbx_vector_discoverer_drule_error_t *errors,
 
 	derror_ptr->error = zbx_dsprintf(derror_ptr->error, "%s\n%s", derror_ptr->error, error);
 }
+
+zbx_discoverer_task_t	*discoverer_queue_snmp_task_get(zbx_discoverer_queue_t *queue, zbx_discoverer_task_t *task,
+		zbx_discoverer_task_t *first_task, int log_worker_id)
+{
+	zbx_discoverer_task_t	*ret_task = NULL;
+	zbx_uint64_t		task_druleid = NULL == task ? 0 : GET_DRULEID(task);
+	zbx_list_iterator_t	job_li, task_li;
+
+	zabbix_log(LOG_LEVEL_DEBUG, "[%d] In %s() first [druleid:" ZBX_FS_UI64 " task type:%d dcheck:"
+			ZBX_FS_UI64 "] task druleid:" ZBX_FS_UI64 " dcheck:" ZBX_FS_UI64, log_worker_id, __func__,
+			GET_DRULEID(first_task), GET_DTYPE(first_task), GET_DCHECKID(first_task),
+			task_druleid, 0 == task_druleid ? 0 : GET_DCHECKID(task));
+
+	if (task == first_task)
+		goto out;
+
+	discoverer_queue_lock(queue);
+
+	zbx_list_iterator_init(&queue->jobs, &job_li);
+
+	while (SUCCEED == zbx_list_iterator_next(&job_li))
+	{
+		zbx_discoverer_job_t	*job;
+
+		if (FAIL == zbx_list_iterator_peek(&job_li, (void**)&job))
+			break;
+
+		zbx_list_iterator_init(&job->tasks, &task_li);
+
+		while (SUCCEED == zbx_list_iterator_next(&task_li))
+		{
+			unsigned char	dtype;
+
+			if (FAIL == zbx_list_iterator_peek(&task_li, (void**)&ret_task))
+				break;
+
+			if (NULL != task && task == ret_task)
+			{
+				ret_task = NULL;
+				continue;
+			}
+
+			dtype = GET_DTYPE(ret_task);
+
+			if (SVC_SNMPv3 != dtype && SVC_SNMPv2c != dtype && SVC_SNMPv1 != dtype)
+			{
+				ret_task = NULL;
+				continue;
+			}
+
+			/* task can be completed by another worker and has not yet been deleted */
+			if (0 == discoverer_task_check_count_get(ret_task))
+			{
+				ret_task = NULL;
+				continue;
+			}
+
+			break;
+		}
+
+		if (NULL != ret_task)
+			break;
+	}
+
+	discoverer_queue_unlock(queue);
+
+	if (NULL == ret_task)
+		ret_task = first_task;
+out:
+	if (NULL != ret_task)
+	{
+		zabbix_log(LOG_LEVEL_DEBUG, "[%d] End of %s() drule:" ZBX_FS_UI64 " task type:%d dcheck:" ZBX_FS_UI64
+				" range count:" ZBX_FS_UI64 " id:" ZBX_FS_UI64 , log_worker_id, __func__,
+				GET_DRULEID(ret_task), GET_DTYPE(ret_task), GET_DCHECKID(ret_task),
+				discoverer_task_check_count_get(ret_task), ret_task->range.id);
+	}
+	else
+		zabbix_log(LOG_LEVEL_DEBUG, "[%d] End of %s() task is NULL", log_worker_id, __func__);
+
+	return ret_task;
+}
diff --git a/src/libs/zbxdiscoverer/discoverer_queue.h b/src/libs/zbxdiscoverer/discoverer_queue.h
index 97616c00bc1..b29dc47f6b5 100644
--- a/src/libs/zbxdiscoverer/discoverer_queue.h
+++ b/src/libs/zbxdiscoverer/discoverer_queue.h
@@ -21,7 +21,7 @@ typedef struct
 {
 	int					workers_num;
 	zbx_list_t				jobs;
-	zbx_uint64_t				pending_checks_count;
+	zbx_uint64_t				pending_checks_count;	/* ZBX_IPC_DISCOVERER_QUEUE */
 	int					snmp_allowed_workers;
 	int					checks_per_worker_max;
 	pthread_mutex_t				lock;
@@ -45,7 +45,9 @@ int	discoverer_queue_init(zbx_discoverer_queue_t *queue, int snmpv3_allowed_work
 void	discoverer_queue_clear_jobs(zbx_list_t *jobs);
 void	discoverer_queue_push(zbx_discoverer_queue_t *queue, zbx_discoverer_job_t *job);
 void	discoverer_queue_append_error(zbx_vector_discoverer_drule_error_t *errors, zbx_uint64_t druleid,
-			const char *error);
+		const char *error);
 
 zbx_discoverer_job_t	*discoverer_queue_pop(zbx_discoverer_queue_t *queue);
+zbx_discoverer_task_t	*discoverer_queue_snmp_task_get(zbx_discoverer_queue_t *queue, zbx_discoverer_task_t *task,
+				zbx_discoverer_task_t *first_task, int log_worker_id);
 #endif
diff --git a/src/libs/zbxdiscoverer/discoverer_snmp.c b/src/libs/zbxdiscoverer/discoverer_snmp.c
new file mode 100644
index 00000000000..e9e999b38b1
--- /dev/null
+++ b/src/libs/zbxdiscoverer/discoverer_snmp.c
@@ -0,0 +1,338 @@
+/*
+** Copyright (C) 2001-2026 Zabbix SIA
+**
+** This program is free software: you can redistribute it and/or modify it under the terms of
+** the GNU Affero General Public License as published by the Free Software Foundation, version 3.
+**
+** 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 Affero General Public License for more details.
+**
+** You should have received a copy of the GNU Affero General Public License along with this program.
+** If not, see <https://www.gnu.org/licenses/>.
+**/
+
+#include "discoverer_snmp.h"
+#include "discoverer_async.h"
+#include "../../libs/zbxpoller/checks_snmp.h"
+#include "../../libs/zbxpoller/async_agent.h"
+#include "zbxsysinfo.h"
+#include "zbx_discoverer_constants.h"
+#include "zbxpoller.h"
+
+static ZBX_THREAD_LOCAL int log_worker_id;
+
+#ifdef HAVE_NETSNMP
+static void	process_snmp_result(void *data)
+{
+	discovery_async_result_t	*async_result = zbx_async_check_snmp_get_arg(data);
+	zbx_dc_item_context_t	*item = zbx_async_check_snmp_get_item_context(data);
+	char			**pvalue;
+
+	zabbix_log(LOG_LEVEL_DEBUG, "[%d] In %s() key:'%s' host:'%s' addr:'%s' ret:%s", log_worker_id, __func__,
+			item->key, item->host, item->interface.addr, zbx_result_string(item->ret));
+
+	async_result->poller_config->processing--;
+	async_result->dresult->processed_checks_per_ip++;
+
+	if (SUCCEED == item->ret && NULL != (pvalue = ZBX_GET_TEXT_RESULT(&item->result)))
+	{
+		zbx_discoverer_dservice_t	*service;
+
+		service = result_dservice_create(item->interface.port, async_result->dcheckid);
+		zbx_strlcpy_utf8(service->value, *pvalue, ZBX_MAX_DISCOVERED_VALUE_SIZE);
+		service->status = DOBJECT_STATUS_UP;
+		zbx_vector_discoverer_services_ptr_append(&async_result->dresult->services, service);
+
+		if (NULL ==  async_result->dresult->dnsname || '\0' == *async_result->dresult->dnsname)
+		{
+			const char	*rdns = ZBX_NULL2EMPTY_STR(zbx_async_check_snmp_get_reverse_dns(data));
+
+			if ('\0' != *rdns && SUCCEED != zbx_validate_hostname(rdns))
+				rdns = "";
+
+			async_result->dresult->dnsname = zbx_strdup(async_result->dresult->dnsname, rdns);
+		}
+	}
+
+	zbx_free(async_result);
+	zbx_async_check_snmp_clean(data);
+
+	zabbix_log(LOG_LEVEL_DEBUG, "[%d] End of %s()", log_worker_id, __func__);
+}
+
+static int	discovery_snmp(discovery_poller_config_t *poller_config, const zbx_dc_dcheck_t *dcheck,
+		char *ip, const unsigned short port, zbx_discoverer_results_t *dresult, char **error)
+{
+	int				ret;
+	zbx_dc_item_t			item;
+	AGENT_RESULT			result;
+	discovery_async_result_t	*async_result;
+
+	async_result = (discovery_async_result_t *) zbx_malloc(NULL, sizeof(discovery_async_result_t));
+	async_result->dresult = dresult;
+	async_result->poller_config = poller_config;
+	async_result->dcheckid = dcheck->dcheckid;
+
+	zbx_init_agent_result(&result);
+
+	memset(&item, 0, sizeof(zbx_dc_item_t));
+	zbx_strscpy(item.key_orig, dcheck->key_);
+	item.key = item.key_orig;
+
+	item.interface.useip = 1;
+	zbx_strscpy(item.interface.ip_orig, ip);
+	item.interface.addr = item.interface.ip_orig;
+	item.interface.port = port;
+
+	item.value_type = ITEM_VALUE_TYPE_STR;
+
+	switch (dcheck->type)
+	{
+		case SVC_SNMPv1:
+			item.snmp_version = ZBX_IF_SNMP_VERSION_1;
+			item.type = ITEM_TYPE_SNMP;
+			break;
+		case SVC_SNMPv2c:
+			item.snmp_version = ZBX_IF_SNMP_VERSION_2;
+			item.type = ITEM_TYPE_SNMP;
+			break;
+		case SVC_SNMPv3:
+			item.snmp_version = ZBX_IF_SNMP_VERSION_3;
+			item.type = ITEM_TYPE_SNMP;
+	}
+
+	item.snmp_community = zbx_strdup(NULL, dcheck->snmp_community);
+	item.snmp_oid = dcheck->key_;
+	item.timeout = dcheck->timeout;
+
+	if (ZBX_IF_SNMP_VERSION_3 == item.snmp_version)
+	{
+		item.snmpv3_securityname = zbx_strdup(NULL, dcheck->snmpv3_securityname);
+		item.snmpv3_authpassphrase = zbx_strdup(NULL, dcheck->snmpv3_authpassphrase);
+		item.snmpv3_privpassphrase = zbx_strdup(NULL, dcheck->snmpv3_privpassphrase);
+
+		item.snmpv3_contextname = zbx_strdup(NULL, dcheck->snmpv3_contextname);
+
+		item.snmpv3_securitylevel = dcheck->snmpv3_securitylevel;
+		item.snmpv3_authprotocol = dcheck->snmpv3_authprotocol;
+		item.snmpv3_privprotocol = dcheck->snmpv3_privprotocol;
+	}
+
+	zbx_set_snmp_bulkwalk_options(poller_config->progname);
+
+	if (SUCCEED != (ret = zbx_async_check_snmp(&item, &result, process_snmp_result, async_result, NULL,
+			poller_config->base, NULL, poller_config->dnsbase, poller_config->config_source_ip,
+			ZABBIX_ASYNC_RESOLVE_REVERSE_DNS_YES, 0)))
+	{
+		if (ZBX_ISSET_MSG(&result))
+			*error = zbx_strdup(*error, *ZBX_GET_MSG_RESULT(&result));
+		else
+			*error = zbx_strdup(*error, "Error of snmp check");
+
+		zbx_free(async_result);
+	}
+	else
+		poller_config->processing++;
+
+	zbx_free(item.snmp_community);
+	zbx_free(item.snmpv3_securityname);
+	zbx_free(item.snmpv3_authpassphrase);
+	zbx_free(item.snmpv3_privpassphrase);
+	zbx_free(item.snmpv3_contextname);
+	zbx_free_agent_result(&result);
+
+	zabbix_log(LOG_LEVEL_DEBUG, "[%d] %s() ip:%s port:%d, key:%s ret:%d", log_worker_id, __func__,
+			ip, port, item.key_orig, ret);
+	return ret;
+}
+#endif
+
+static int	snmp_jobs_total_concurrency(zbx_discoverer_manager_t *dmanager)
+{
+	int	cuncurrent_check_max = 0;
+
+	discoverer_queue_lock(&dmanager->queue);
+
+	for (int i = 0; i < dmanager->job_refs.values_num; i++)
+	{
+		int			is_snmp = FAIL;
+		zbx_discoverer_job_t	*job = dmanager->job_refs.values[i];
+		zbx_list_iterator_t	li;
+
+		zbx_list_iterator_init(&job->tasks, &li);
+
+		do
+		{
+			zbx_discoverer_task_t	*task;
+			unsigned char		dtype;
+
+			if (FAIL == zbx_list_iterator_peek(&li, (void*)&task))
+				break;
+
+			dtype = GET_DTYPE(task);
+
+			if (SVC_SNMPv3 == dtype || SVC_SNMPv2c == dtype || SVC_SNMPv1 == dtype)
+			{
+				is_snmp = SUCCEED;
+				break;
+			}
+		}
+		while (SUCCEED == zbx_list_iterator_next(&li));
+
+		if (FAIL == is_snmp)
+			continue;
+
+		if (0 != job->concurrency_max && job->concurrency_max < dmanager->queue.checks_per_worker_max)
+			cuncurrent_check_max += job->concurrency_max;
+	}
+
+	discoverer_queue_unlock(&dmanager->queue);
+
+	zabbix_log(LOG_LEVEL_TRACE, "[%d] %s() cuncurrent_check_max:%d", log_worker_id, __func__,
+			cuncurrent_check_max);
+
+	if (DISCOVERER_SNMP_CHECKS_INPROGRESS_MAX < cuncurrent_check_max || (0 == cuncurrent_check_max &&
+			DISCOVERER_JOB_TASKS_INPROGRESS_MAX == dmanager->queue.checks_per_worker_max))
+	{
+		cuncurrent_check_max = DISCOVERER_SNMP_CHECKS_INPROGRESS_MAX;
+	}
+	else
+		cuncurrent_check_max = dmanager->queue.checks_per_worker_max;
+
+	return cuncurrent_check_max;
+}
+
+static int	discovery_task_is_finished(const zbx_discoverer_task_t *task, zbx_uint64_t druleid)
+{
+	int ret = (0 == discoverer_task_check_count_get(task) ? SUCCEED : FAIL);
+
+	zabbix_log(LOG_LEVEL_DEBUG, "[%d] %s() druleid:" ZBX_FS_UI64 " type:%u ret:%s", log_worker_id, __func__,
+			druleid, GET_DTYPE(task), SUCCEED == ret ? "SUCCEED" : "FAIL");
+	return ret;
+}
+
+int	discovery_jobs_check_snmp(zbx_uint64_t druleid, zbx_discoverer_task_t *first_task, int concurrency_max,
+		int *stop, zbx_discoverer_manager_t *dmanager, int worker_id, char **error)
+{
+	zbx_vector_discoverer_results_ptr_t	results;
+	discovery_poller_config_t		poller_config;
+	char					ip[ZBX_INTERFACE_IP_LEN_MAX], first_ip[ZBX_INTERFACE_IP_LEN_MAX];
+	int					ret = FAIL, abort = SUCCEED, is_snmpv3 = FAIL, drule_n = 0, task_n = 0,
+						check_n = 0;
+	zbx_uint64_t				dec_counter = 0;
+	zbx_discoverer_task_t			*task = NULL;
+
+	if (0 == log_worker_id)
+		log_worker_id = worker_id;
+
+	zabbix_log(LOG_LEVEL_DEBUG, "[%d] In %s() job_refs:%d first druleid:" ZBX_FS_UI64 " range id:" ZBX_FS_UI64
+			" type:%u state.count:" ZBX_FS_UI64, log_worker_id, __func__, dmanager->job_refs.values_num,
+			druleid, first_task->range.id, GET_DTYPE(first_task),
+			discoverer_task_check_count_get(first_task));
+
+	*first_ip = *ip = '\0';
+#ifndef HAVE_NETSNMP
+	*error = zbx_strdup(*error, "Support for SNMP checks was not compiled in.");
+	goto general_fail;
+#endif
+	if (SUCCEED == (ret = discovery_task_is_finished(first_task, druleid)))
+		goto general_fail;
+
+	concurrency_max = snmp_jobs_total_concurrency(dmanager);
+
+	if (SUCCEED != discovery_async_poller_init(dmanager, &poller_config))
+	{
+		*error = zbx_strdup(*error, "Cannot initialize discovery async poller.");
+		goto general_fail;
+	}
+
+	zbx_vector_discoverer_results_ptr_create(&results);
+	druleid = 0;
+
+	while (NULL != (task = discoverer_queue_snmp_task_get(&dmanager->queue, task, first_task, log_worker_id)) &&
+			0 == *stop && SUCCEED == abort)
+	{
+		if (druleid != GET_DRULEID(task))
+		{
+			druleid = GET_DRULEID(task);
+			drule_n++;
+		}
+
+		task_n++;
+		zabbix_log(LOG_LEVEL_DEBUG, "[%d] %s() start druleid:" ZBX_FS_UI64 " range id:" ZBX_FS_UI64
+				" state.count:" ZBX_FS_UI64 " checks per ip:%u dchecks:%d type:%u concurrency_max:%d "
+				"checks_per_worker_max:%d drule_n:%d task_n:%d check_n:%d", log_worker_id, __func__,
+				druleid, task->range.id, discoverer_task_check_count_get(task),
+				task->range.state.checks_per_ip, task->ds_dchecks.values_num, GET_DTYPE(task),
+				concurrency_max, dmanager->queue.checks_per_worker_max, drule_n, task_n, check_n);
+
+		if (SVC_SNMPv3 == GET_DTYPE(task))
+			is_snmpv3 = SUCCEED;
+
+		do
+		{
+			zbx_discoverer_results_t	*result;
+			zbx_dc_dcheck_t			*dcheck;
+
+			TASK_IP2STR(task, ip);
+
+			if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_DEBUG) && '\0' == *first_ip)
+				zbx_strlcpy(first_ip, ip, sizeof(first_ip));
+
+			result = discoverer_result_create(druleid, task);
+			result->ip = zbx_strdup(NULL, ip);
+			zbx_vector_discoverer_results_ptr_append(&results, result);
+			dcheck = &task->ds_dchecks.values[task->range.state.index_dcheck]->dcheck;
+			check_n++;
+
+			ret = discovery_snmp(&poller_config, dcheck, ip,
+					(unsigned short)task->range.state.port, result, error);
+
+			if (FAIL == ret)
+				goto out;
+
+			while (concurrency_max == poller_config.processing)
+				event_base_loop(poller_config.base, EVLOOP_ONCE);
+
+			abort = discovery_net_check_result_flush(dmanager, &results, 0);
+
+			if (SUCCEED == discovery_pending_checks_count_decrease(&dmanager->queue, concurrency_max,
+					task->range.state.count, ++dec_counter))
+			{
+				dec_counter = 0;
+			}
+		}			/* we have to decrease range.state.count before exit by abort*/
+		while (0 == *stop && SUCCEED == discoverer_range_check_iter(task) && SUCCEED == abort);
+
+		(void)discovery_pending_checks_count_decrease(&dmanager->queue, concurrency_max, 0,
+				task->range.state.count + dec_counter);
+
+		zabbix_log(LOG_LEVEL_DEBUG, "[%d] %s() end druleid:" ZBX_FS_UI64 " type:%u state.count:" ZBX_FS_UI64
+				" first ip:%s last ip:%s abort:%d ret:%d drule_n:%d task_n:%d check_n:%d",
+				log_worker_id, __func__, druleid, GET_DTYPE(task),
+				discoverer_task_check_count_get(task), first_ip, ip, abort, ret, drule_n, task_n,
+				check_n);
+		*first_ip = '\0';
+	}
+out:
+	while (0 != poller_config.processing)	/* try to close all handles if they are exhausted */
+	{
+		event_base_loop(poller_config.base, EVLOOP_ONCE);
+		discovery_net_check_result_flush(dmanager, &results, 0);
+	}
+
+	discovery_net_check_result_flush(dmanager, &results, 1);
+	zbx_vector_discoverer_results_ptr_clear_ext(&results, results_free);	/* Incomplete results*/
+	zbx_vector_discoverer_results_ptr_destroy(&results);
+	discovery_async_poller_destroy(&poller_config);
+	/* we must clear the EnginID cache before the next snmpv3 dcheck and */
+	/* remove unused collected values in any case */
+	if (SUCCEED == is_snmpv3)
+		zbx_clear_cache_snmp(dmanager->process_type, FAIL);
+general_fail:
+	zabbix_log(LOG_LEVEL_DEBUG, "[%d] End of %s()  drule_n:%d task_n:%d check_n:%d abort:%d ret:%d", log_worker_id,
+			__func__, drule_n, task_n, check_n, abort, ret);
+
+	return ret;
+}
diff --git a/src/libs/zbxdiscoverer/discoverer_snmp.h b/src/libs/zbxdiscoverer/discoverer_snmp.h
new file mode 100644
index 00000000000..1cebe1977cc
--- /dev/null
+++ b/src/libs/zbxdiscoverer/discoverer_snmp.h
@@ -0,0 +1,23 @@
+/*
+** Copyright (C) 2001-2026 Zabbix SIA
+**
+** This program is free software: you can redistribute it and/or modify it under the terms of
+** the GNU Affero General Public License as published by the Free Software Foundation, version 3.
+**
+** 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 Affero General Public License for more details.
+**
+** You should have received a copy of the GNU Affero General Public License along with this program.
+** If not, see <https://www.gnu.org/licenses/>.
+**/
+
+#ifndef ZABBIX_DISCOVERER_SNMP_H_
+#define ZABBIX_DISCOVERER_SNMP_H_
+
+#include "discoverer_int.h"
+
+int	discovery_jobs_check_snmp(zbx_uint64_t druleid, zbx_discoverer_task_t *task, int concurrency_max, int *stop,
+		zbx_discoverer_manager_t *dmanager, int worker_id, char **error);
+
+#endif /* ZABBIX_DISCOVERER_SNMP_H_ */
diff --git a/src/libs/zbxdiscoverer/discoverer_taskprep.c b/src/libs/zbxdiscoverer/discoverer_taskprep.c
index 5e035afbb02..ef3caeb614c 100644
--- a/src/libs/zbxdiscoverer/discoverer_taskprep.c
+++ b/src/libs/zbxdiscoverer/discoverer_taskprep.c
@@ -107,7 +107,7 @@ static zbx_ds_dcheck_t	*dcheck_clone_get(zbx_dc_dcheck_t *dcheck, zbx_vector_ds_
 static zbx_uint64_t	process_check_range(const zbx_dc_drule_t *drule, zbx_ds_dcheck_t *ds_dcheck,
 		zbx_vector_iprange_t *ipranges, zbx_hashset_t *tasks)
 {
-	zbx_discoverer_task_t	task_local, *task;
+	zbx_discoverer_task_t	task_local = {0}, *task;
 	int			port = ZBX_PORTRANGE_INIT_PORT;
 	unsigned int		checks_count = 0;
 
@@ -124,7 +124,6 @@ static zbx_uint64_t	process_check_range(const zbx_dc_drule_t *drule, zbx_ds_dche
 	else
 		checks_count = 1;
 
-	task_local.range.id = 0;
 	zbx_vector_ds_dcheck_ptr_create(&task_local.ds_dchecks);
 	zbx_vector_ds_dcheck_ptr_append(&task_local.ds_dchecks, ds_dcheck);
 
diff --git a/src/libs/zbxicmpping/icmpping.c b/src/libs/zbxicmpping/icmpping.c
index 7cb1a661706..a9b4964ac93 100644
--- a/src/libs/zbxicmpping/icmpping.c
+++ b/src/libs/zbxicmpping/icmpping.c
@@ -532,8 +532,7 @@ static int	check_hostip_response(char *resp, zbx_fping_host_t *hosts, const int
 
 	for (i = 0; i < hosts_count; i++)
 	{
-		if ((0 != rdns && SUCCEED == zbx_ip_in_list(tmp, hosts[i].addr)) ||
-				(0 == rdns && 0 == strcmp(tmp, hosts[i].addr)))
+		if (0 == strcmp(tmp, hosts[i].addr))
 		{
 			*host = &hosts[i];
 			ret = SUCCEED;
@@ -541,6 +540,19 @@ static int	check_hostip_response(char *resp, zbx_fping_host_t *hosts, const int
 		}
 	}
 
+	if (FAIL == ret && 0 != rdns)
+	{
+		for (i = 0; i < hosts_count; i++)
+		{
+			if (SUCCEED == zbx_ip_in_list(tmp, hosts[i].addr))
+			{
+				*host = &hosts[i];
+				ret = SUCCEED;
+				break;
+			}
+		}
+	}
+
 	*c = (0 == rdns) ? ' ' : ')';
 
 	return ret;
