diff --git a/Documentation/kbuild/kconfig.rst b/Documentation/kbuild/kconfig.rst
index 6530ecd99da3..445c438dc741 100644
--- a/Documentation/kbuild/kconfig.rst
+++ b/Documentation/kbuild/kconfig.rst
@@ -29,6 +29,14 @@ To see a list of new config symbols, use::
 
 and the config program will list any new symbols, one per line.
 
+To see a list of config symbols that are not recognized anymore (e.g.
+removed or renamed), use::
+
+	cp user/some/old.config .config
+	make listunknownconfig
+
+and the config program will list any unrecognized symbols, one per line.
+
 Alternatively, you can use the brute force method::
 
 	make oldconfig
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index af1c96198f49..942316ddebd9 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -69,7 +69,8 @@ localyesconfig localmodconfig: $(obj)/conf
 #  deprecated for external use
 simple-targets := oldconfig allnoconfig allyesconfig allmodconfig \
 	alldefconfig randconfig listnewconfig olddefconfig syncconfig \
-	helpnewconfig yes2modconfig mod2yesconfig mod2noconfig
+	helpnewconfig yes2modconfig mod2yesconfig mod2noconfig \
+	listunknownconfig
 
 PHONY += $(simple-targets)
 
@@ -141,6 +142,7 @@ help:
 	@echo  '                    default value without prompting'
 	@echo  '  tinyconfig	  - Configure the tiniest possible kernel'
 	@echo  '  testconfig	  - Run Kconfig unit tests (requires python3 and pytest)'
+	@echo  '  listunknownconfig	- List unrecognized options'
 
 # ===========================================================================
 # object files used by all kconfig flavours
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index 33d19e419908..e26aa491be00 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -36,6 +36,7 @@ enum input_mode {
 	yes2modconfig,
 	mod2yesconfig,
 	mod2noconfig,
+	listunknownconfig,
 };
 static enum input_mode input_mode = oldaskconfig;
 static int input_mode_opt;
@@ -683,6 +684,7 @@ static const struct option long_opts[] = {
 	{"yes2modconfig", no_argument,       &input_mode_opt, yes2modconfig},
 	{"mod2yesconfig", no_argument,       &input_mode_opt, mod2yesconfig},
 	{"mod2noconfig",  no_argument,       &input_mode_opt, mod2noconfig},
+	{"listunknownconfig", no_argument,   &input_mode_opt, listunknownconfig},
 	{NULL, 0, NULL, 0}
 };
 
@@ -712,6 +714,7 @@ static void conf_usage(const char *progname)
 	printf("  --yes2modconfig         Change answers from yes to mod if possible\n");
 	printf("  --mod2yesconfig         Change answers from mod to yes if possible\n");
 	printf("  --mod2noconfig          Change answers from mod to no if possible\n");
+	printf("  --listunknownconfig     List config options that do not exist anymore\n");
 	printf("  (If none of the above is given, --oldaskconfig is the default)\n");
 }
 
@@ -823,6 +826,11 @@ int main(int ac, char **av)
 			exit(1);
 		}
 		break;
+	case listunknownconfig:
+		if (conf_read_list_unknown())
+			exit(1);
+		exit(0);
+		break;
 	default:
 		break;
 	}
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
index 992575f1e976..d387a4f08cef 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -341,6 +341,61 @@ static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream)
 	return -1;
 }
 
+int conf_read_list_unknown(void)
+{
+	FILE *in = NULL;
+	size_t line_asize = 0;
+	char *line = NULL;
+	char *p, *p2;
+	struct symbol *sym;
+
+	conf_filename = conf_get_configname();
+	in = zconf_fopen(conf_filename);
+	if (!in)
+		return -1;
+
+	while (compat_getline(&line, &line_asize, in) != -1) {
+		conf_lineno++;
+		sym = NULL;
+		if (line[0] == '#') {
+			if (memcmp(line + 2, CONFIG_, strlen(CONFIG_)))
+				continue;
+			p = strchr(line + 2 + strlen(CONFIG_), ' ');
+			if (!p)
+				continue;
+			*p++ = 0;
+			sym = sym_find(line + 2 + strlen(CONFIG_));
+			if (!sym) {
+				conf_warning("unknown unset symbol: %s",
+					     line + 2 + strlen(CONFIG_));
+				continue;
+			}
+		} else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) {
+			p = strchr(line + strlen(CONFIG_), '=');
+			if (!p)
+				continue;
+			*p++ = 0;
+			p2 = strchr(p, '\n');
+			if (p2) {
+				*p2-- = 0;
+				if (*p2 == '\r')
+					*p2 = 0;
+			}
+
+			sym = sym_find(line + strlen(CONFIG_));
+			if (!sym) {
+				conf_warning("unknown symbol: %s",
+					     line + strlen(CONFIG_));
+				continue;
+			}
+		}
+	}
+
+	free(line);
+	fclose(in);
+	return conf_warnings;
+}
+
 int conf_read_simple(const char *name, int def)
 {
 	FILE *in = NULL;
diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h
index edd1e617b25c..bb60b1669750 100644
--- a/scripts/kconfig/lkc_proto.h
+++ b/scripts/kconfig/lkc_proto.h
@@ -5,6 +5,7 @@
 void conf_parse(const char *name);
 int conf_read(const char *name);
 int conf_read_simple(const char *name, int);
+int conf_read_list_unknown(void);
 int conf_write_defconfig(const char *name);
 int conf_write(const char *name);
 int conf_write_autoconf(int overwrite);
