diff --git a/vpn/plugins/wireguard.c b/vpn/plugins/wireguard.c
index de57b15f..2c5981f8 100644
--- a/vpn/plugins/wireguard.c
+++ b/vpn/plugins/wireguard.c
@@ -50,9 +50,11 @@
 #include "wireguard.h"
 
 #define DNS_RERESOLVE_TIMEOUT 20
+#define DNS_RERESOLVE_ERROR_LIMIT 5
 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
 
 struct wireguard_info {
+	struct vpn_provider *provider;
 	struct wg_device device;
 	struct wg_peer peer;
 	char *endpoint_fqdn;
@@ -155,6 +157,7 @@ static int parse_endpoint(const char *host, const char *port, struct sockaddr_u
 	struct addrinfo hints;
 	struct addrinfo *result, *rp;
 	int sk;
+	int err;
 
 	memset(&hints, 0, sizeof(struct addrinfo));
 	hints.ai_family = AF_UNSPEC;
@@ -162,8 +165,9 @@ static int parse_endpoint(const char *host, const char *port, struct sockaddr_u
 	hints.ai_flags = 0;
 	hints.ai_protocol = 0;
 
-	if (getaddrinfo(host, port, &hints, &result) < 0) {
-		DBG("Failed to resolve host address");
+	err = getaddrinfo(host, port, &hints, &result);
+	if (err < 0) {
+		DBG("Failed to resolve host address: %s", gai_strerror(err));
 		return -EINVAL;
 	}
 
@@ -287,22 +291,38 @@ static bool sockaddr_cmp_addr(struct sockaddr_u *a, struct sockaddr_u *b)
 	return false;
 }
 
+static void run_dns_reresolve(struct wireguard_info *info);
+
 static gboolean wg_dns_reresolve_cb(gpointer user_data)
 {
 	struct wireguard_info *info = user_data;
 	struct sockaddr_u addr;
 	int err;
 
-	DBG("");
+	if (vpn_provider_get_connection_errors(info->provider) >=
+						DNS_RERESOLVE_ERROR_LIMIT) {
+		connman_warn("reresolve error limit reached");
+		vpn_died(NULL, -ENONET, info->provider);
+		return G_SOURCE_REMOVE;
+	}
 
+	/* If this fails after being connected it means configuration error
+	 * that results in connection errors. */
 	err = parse_endpoint(info->endpoint_fqdn,
 			info->port, &addr);
-	if (err)
-		return TRUE;
+	if (err) {
+		if (info->provider)
+			vpn_provider_add_error(info->provider,
+					VPN_PROVIDER_ERROR_CONNECT_FAILED);
+		run_dns_reresolve(info);
+		return G_SOURCE_REMOVE;
+	}
 
 	if (sockaddr_cmp_addr(&addr,
-			(struct sockaddr_u *)&info->peer.endpoint.addr))
-		return TRUE;
+			(struct sockaddr_u *)&info->peer.endpoint.addr)) {
+		run_dns_reresolve(info);
+		return G_SOURCE_REMOVE;
+	}
 
 	if (addr.sa.sa_family == AF_INET)
 		memcpy(&info->peer.endpoint.addr, &addr.sin,
@@ -317,7 +337,17 @@ static gboolean wg_dns_reresolve_cb(gpointer user_data)
 		DBG("Failed to update Endpoint address for WireGuard device %s",
 			info->device.name);
 
-	return TRUE;
+	run_dns_reresolve(info);
+	return G_SOURCE_REMOVE;
+}
+
+static void run_dns_reresolve(struct wireguard_info *info)
+{
+	if (info->reresolve_id)
+		g_source_remove(info->reresolve_id);
+
+	info->reresolve_id = g_timeout_add_seconds(DNS_RERESOLVE_TIMEOUT,
+						wg_dns_reresolve_cb, info);
 }
 
 static int wg_connect(struct vpn_provider *provider,
@@ -336,8 +366,12 @@ static int wg_connect(struct vpn_provider *provider,
 	info->device.flags = WGDEVICE_HAS_PRIVATE_KEY;
 	info->device.first_peer = &info->peer;
 	info->device.last_peer = &info->peer;
+	info->provider = vpn_provider_ref(provider);
+
+	DBG("");
 
 	vpn_provider_set_plugin_data(provider, info);
+	vpn_provider_set_auth_error_limit(provider, 1);
 
 	option = vpn_provider_get_string(provider, "WireGuard.ListenPort");
 	if (option) {
@@ -351,30 +385,30 @@ static int wg_connect(struct vpn_provider *provider,
 		err = vpn_provider_set_nameservers(provider, option);
 		if (err) {
 			DBG("Cannot set nameservers %s", option);
-			goto done;
+			goto error;
 		}
 	}
 
 	option = vpn_provider_get_string(provider, "WireGuard.PrivateKey");
 	if (!option) {
 		DBG("WireGuard.PrivateKey is missing");
-		goto done;
+		goto error;
 	}
 	err = parse_key(option, info->device.private_key);
 	if (err) {
 		DBG("Failed to parse private key");
-		goto done;
+		goto error;
 	}
 
 	option = vpn_provider_get_string(provider, "WireGuard.PublicKey");
 	if (!option) {
 		DBG("WireGuard.PublicKey is missing");
-		goto done;
+		goto error;
 	}
 	err = parse_key(option, info->peer.public_key);
 	if (err) {
 		DBG("Failed to parse public key");
-		goto done;
+		goto error;
 	}
 
 	option = vpn_provider_get_string(provider, "WireGuard.PresharedKey");
@@ -383,19 +417,19 @@ static int wg_connect(struct vpn_provider *provider,
 		err = parse_key(option, info->peer.preshared_key);
 		if (err) {
 			DBG("Failed to parse pre-shared key");
-			goto done;
+			goto error;
 		}
 	}
 
 	option = vpn_provider_get_string(provider, "WireGuard.AllowedIPs");
 	if (!option) {
 		DBG("WireGuard.AllowedIPs is missing");
-		goto done;
+		goto error;
 	}
 	err = parse_allowed_ips(option, &info->peer);
 	if (err) {
 		DBG("Failed to parse allowed IPs %s", option);
-		goto done;
+		goto error;
 	}
 
 	option = vpn_provider_get_string(provider,
@@ -415,8 +449,8 @@ static int wg_connect(struct vpn_provider *provider,
 	err = parse_endpoint(gateway, option,
 			(struct sockaddr_u *)&info->peer.endpoint.addr);
 	if (err) {
-		DBG("Failed to parse endpoint %s gateway %s", option, gateway);
-		goto done;
+		DBG("Failed to parse endpoint %s:%s", gateway, option);
+		goto error;
 	}
 
 	info->endpoint_fqdn = g_strdup(gateway);
@@ -425,12 +459,12 @@ static int wg_connect(struct vpn_provider *provider,
 	option = vpn_provider_get_string(provider, "WireGuard.Address");
 	if (!option) {
 		DBG("Missing WireGuard.Address configuration");
-		goto done;
+		goto error;
 	}
 	err = parse_address(option, gateway, &ipaddress);
 	if (err) {
 		DBG("Failed to parse address %s gateway %s", option, gateway);
-		goto done;
+		goto error;
 	}
 
 	ifname = get_ifname();
@@ -465,16 +499,27 @@ done:
 	connman_ipaddress_free(ipaddress);
 
 	if (!err)
-		info->reresolve_id =
-			g_timeout_add_seconds(DNS_RERESOLVE_TIMEOUT,
-						wg_dns_reresolve_cb, info);
+		run_dns_reresolve(info);
 
 	return err;
+
+error:
+	/*
+	 * TODO: add own category for parameter errors. This is to avoid
+	 * looping when parameters are incorrect and VPN stays in failed
+	 * state.
+	 */
+	vpn_provider_add_error(provider, VPN_PROVIDER_ERROR_LOGIN_FAILED);
+	err = -ECONNABORTED;
+	goto done;
 }
 
 static void wg_disconnect(struct vpn_provider *provider)
 {
 	struct wireguard_info *info;
+	int exit_code;
+
+	DBG("");
 
 	info = vpn_provider_get_plugin_data(provider);
 	if (!info)
@@ -485,11 +530,32 @@ static void wg_disconnect(struct vpn_provider *provider)
 
 	vpn_provider_set_plugin_data(provider, NULL);
 
-	wg_del_device(info->device.name);
+	vpn_provider_set_state(provider, VPN_PROVIDER_STATE_DISCONNECT);
+
+	exit_code = wg_del_device(info->device.name);
 
+	vpn_provider_unref(info->provider);
 	g_free(info->endpoint_fqdn);
 	g_free(info->port);
 	g_free(info);
+
+	DBG("exiting with %d", exit_code);
+
+	/* No task for no daemon VPN - use VPN died with no task. */
+	vpn_died(NULL, exit_code, provider);
+}
+
+static int wg_error_code(struct vpn_provider *provider, int exit_code)
+{
+	DBG("exit_code %d", exit_code);
+
+	switch (exit_code) {
+	/* Failed to parse configuration -> wg_del_device() has no to delete */
+	case -ENODEV:
+		return 0;
+	default:
+		return exit_code;
+	}
 }
 
 static int wg_save(struct vpn_provider *provider, GKeyFile *keyfile)
@@ -518,6 +584,7 @@ static struct vpn_driver vpn_driver = {
 	.connect	= wg_connect,
 	.disconnect	= wg_disconnect,
 	.save		= wg_save,
+	.error_code	= wg_error_code
 };
 
 static int wg_init(void)
