diff --git a/src/scan.c b/src/scan.c
index d3f0ad31..8699fe3e 100644
--- a/src/scan.c
+++ b/src/scan.c
@@ -132,6 +132,18 @@ struct scan_context {
 	 */
 	unsigned int get_fw_scan_cmd_id;
 	struct wiphy *wiphy;
+
+	unsigned int get_survey_cmd_id;
+};
+
+struct scan_survey {
+	int8_t noise;
+};
+
+struct scan_survey_results {
+	struct scan_survey survey_2_4[14];
+	struct scan_survey survey_5[196];
+	struct scan_survey survey_6[233];
 };
 
 struct scan_results {
@@ -140,6 +152,9 @@ struct scan_results {
 	uint64_t time_stamp;
 	struct scan_request *sr;
 	struct scan_freq_set *freqs;
+	struct scan_survey_results survey;
+
+	bool survey_parsed : 1;
 };
 
 static bool start_next_scan_request(struct wiphy_radio_work_item *item);
@@ -217,6 +232,9 @@ static void scan_context_free(struct scan_context *sc)
 	if (sc->get_fw_scan_cmd_id && nl80211)
 		l_genl_family_cancel(nl80211, sc->get_fw_scan_cmd_id);
 
+	if (sc->get_survey_cmd_id && nl80211)
+		l_genl_family_cancel(nl80211, sc->get_survey_cmd_id);
+
 	wiphy_state_watch_remove(sc->wiphy, sc->wiphy_watch_id);
 
 	l_free(sc);
@@ -1663,6 +1681,8 @@ static void scan_bss_compute_rank(struct scan_bss *bss)
 {
 	static const double RANK_HIGH_UTILIZATION_FACTOR = 0.8;
 	static const double RANK_LOW_UTILIZATION_FACTOR = 1.2;
+	static const double RANK_HIGH_SNR_FACTOR = 1.2;
+	static const double RANK_LOW_SNR_FACTOR = 0.8;
 	double rank;
 	uint32_t irank;
 	/*
@@ -1689,6 +1709,13 @@ static void scan_bss_compute_rank(struct scan_bss *bss)
 	else if (bss->utilization <= 63)
 		rank *= RANK_LOW_UTILIZATION_FACTOR;
 
+	if (bss->have_snr) {
+		if (bss->snr <= 15)
+			rank *= RANK_LOW_SNR_FACTOR;
+		else if (bss->snr >= 30)
+			rank *= RANK_HIGH_SNR_FACTOR;
+	}
+
 	irank = rank;
 
 	if (irank > USHRT_MAX)
@@ -1824,6 +1851,41 @@ int scan_bss_rank_compare(const void *a, const void *b, void *user_data)
 	return (bss->rank > new_bss->rank) ? 1 : -1;
 }
 
+static bool scan_survey_get_snr(struct scan_results *results,
+					uint32_t freq, int32_t signal,
+					int8_t *snr)
+{
+	uint8_t channel;
+	enum band_freq band;
+	int8_t noise = 0;
+
+	if (!results->survey_parsed)
+		return false;
+
+	channel = band_freq_to_channel(freq, &band);
+	if (L_WARN_ON(!channel))
+		return false;
+
+	switch (band) {
+	case BAND_FREQ_2_4_GHZ:
+		noise = results->survey.survey_2_4[channel].noise;
+		break;
+	case BAND_FREQ_5_GHZ:
+		noise = results->survey.survey_5[channel].noise;
+		break;
+	case BAND_FREQ_6_GHZ:
+		noise = results->survey.survey_6[channel].noise;
+		break;
+	}
+
+	if (noise) {
+		*snr = signal - noise;
+		return true;
+	}
+
+	return false;
+}
+
 static void get_scan_callback(struct l_genl_msg *msg, void *user_data)
 {
 	struct scan_results *results = user_data;
@@ -1849,6 +1911,10 @@ static void get_scan_callback(struct l_genl_msg *msg, void *user_data)
 		bss->time_stamp = results->time_stamp -
 					seen_ms_ago * L_USEC_PER_MSEC;
 
+	bss->have_snr = scan_survey_get_snr(results, bss->frequency,
+						bss->signal_strength / 100,
+						&bss->snr);
+
 	scan_bss_compute_rank(bss);
 	l_queue_insert(results->bss_list, bss, scan_bss_rank_compare, NULL);
 }
@@ -1925,11 +1991,104 @@ static void get_scan_done(void *user)
 	l_free(results);
 }
 
+static void get_survey_callback(struct l_genl_msg *msg, void *user_data)
+{
+	struct scan_results *results = user_data;
+	struct scan_survey_results *survey = &results->survey;
+	struct l_genl_attr attr;
+	uint16_t type, len;
+	const void *data;
+	const uint32_t *freq = NULL;
+	const int8_t *noise = NULL;
+	uint8_t channel;
+	enum band_freq band;
+
+	if (nl80211_parse_attrs(msg, NL80211_ATTR_SURVEY_INFO, &attr,
+				NL80211_ATTR_UNSPEC) < 0)
+		return;
+
+	while (l_genl_attr_next(&attr, &type, &len, &data)) {
+		switch (type) {
+		case NL80211_SURVEY_INFO_FREQUENCY:
+			if (len != 4)
+				return;
+
+			freq = data;
+			break;
+		case NL80211_SURVEY_INFO_NOISE:
+			if (len != 1)
+				return;
+
+			noise = data;
+			break;
+		}
+	}
+
+	if (!freq || !noise)
+		return;
+
+	channel = band_freq_to_channel(*freq, &band);
+	if (!channel)
+		return;
+
+	/* At least one frequency was surveyed */
+	results->survey_parsed = true;
+
+	switch (band) {
+	case BAND_FREQ_2_4_GHZ:
+		survey->survey_2_4[channel].noise = *noise;
+		break;
+	case BAND_FREQ_5_GHZ:
+		survey->survey_5[channel].noise = *noise;
+		break;
+	case BAND_FREQ_6_GHZ:
+		survey->survey_6[channel].noise = *noise;
+		break;
+	}
+}
+
+static void get_results(struct scan_results *results)
+{
+	struct l_genl_msg *scan_msg;
+
+	scan_msg = l_genl_msg_new_sized(NL80211_CMD_GET_SCAN, 8);
+
+	l_genl_msg_append_attr(scan_msg, NL80211_ATTR_WDEV, 8,
+					&results->sc->wdev_id);
+	results->sc->get_scan_cmd_id = l_genl_family_dump(nl80211, scan_msg,
+						get_scan_callback,
+						results, get_scan_done);
+}
+
+static void get_survey_done(void *user_data)
+{
+	struct scan_results *results = user_data;
+	struct scan_context *sc = results->sc;
+
+	sc->get_survey_cmd_id = 0;
+
+	get_results(results);
+}
+
+static bool scan_survey(struct scan_results *results)
+{
+	struct scan_context *sc = results->sc;
+	struct l_genl_msg *survey_msg;
+
+	survey_msg = l_genl_msg_new(NL80211_CMD_GET_SURVEY);
+	l_genl_msg_append_attr(survey_msg, NL80211_ATTR_WDEV, 8,
+				&sc->wdev_id);
+	sc->get_survey_cmd_id = l_genl_family_dump(nl80211, survey_msg,
+						get_survey_callback, results,
+						get_survey_done);
+
+	return sc->get_survey_cmd_id != 0;
+}
+
 static void scan_get_results(struct scan_context *sc, struct scan_request *sr,
 				struct scan_freq_set *freqs)
 {
 	struct scan_results *results;
-	struct l_genl_msg *scan_msg;
 
 	results = l_new(struct scan_results, 1);
 	results->sc = sc;
@@ -1938,13 +2097,12 @@ static void scan_get_results(struct scan_context *sc, struct scan_request *sr,
 	results->bss_list = l_queue_new();
 	results->freqs = freqs;
 
-	scan_msg = l_genl_msg_new_sized(NL80211_CMD_GET_SCAN, 8);
+	if (scan_survey(results))
+		return;
+	else
+		l_warn("failed to start a scan survey");
 
-	l_genl_msg_append_attr(scan_msg, NL80211_ATTR_WDEV, 8,
-					&sc->wdev_id);
-	sc->get_scan_cmd_id = l_genl_family_dump(nl80211, scan_msg,
-						get_scan_callback,
-						results, get_scan_done);
+	get_results(results);
 }
 
 static void scan_wiphy_watch(struct wiphy *wiphy,
diff --git a/src/scan.h b/src/scan.h
index 516b6152..0bfc9e47 100644
--- a/src/scan.h
+++ b/src/scan.h
@@ -75,6 +75,7 @@ struct scan_bss {
 	uint64_t parent_tsf;
 	uint8_t *wfd;		/* Concatenated WFD IEs */
 	ssize_t wfd_size;	/* Size of Concatenated WFD IEs */
+	int8_t snr;
 	bool mde_present : 1;
 	bool cc_present : 1;
 	bool cap_rm_neighbor_report : 1;
@@ -89,6 +90,7 @@ struct scan_bss {
 	bool dpp_configurator : 1;
 	bool sae_pw_id_used : 1;
 	bool sae_pw_id_exclusive : 1;
+	bool have_snr : 1;
 };
 
 struct scan_parameters {
