diff --git a/ChangeLog b/ChangeLog
index a0bf033e..7f42c7fb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2021-11-12  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by Martino Facchin:
+	patch #9110: Let reserved fuse bits to be read as *don't care*
+	* avr.c (compare_memory_masked): New function
+	* libavrdude.h: declare compare_memory_masked(); also, insist on C99
+	so <stdint.h> is required now
+	* main.c: Use compare_memory_masked() in safemode comparisons
+
 2021-11-11  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
 
 	Submitted by Joseph Coffland:
diff --git a/NEWS b/NEWS
index 4875ddbd..791d9750 100644
--- a/NEWS
+++ b/NEWS
@@ -104,6 +104,7 @@ Current:
     patch #9697: Add iseavrprog support
     patch #10017: uspasp / tpi: Automatically clear configuration byte (fuse) before writing it
     patch #8957: Allow reading prodsig memory from stk500v2 on xmega devices
+    patch #9110: Let reserved fuse bits to be read as *don't care*
 
   * Internals:
     - New avrdude.conf keyword "family_id", used to verify SIB attributes
diff --git a/avr.c b/avr.c
index 0f2ae79a..4091b497 100644
--- a/avr.c
+++ b/avr.c
@@ -1063,6 +1063,30 @@ int avr_signature(PROGRAMMER * pgm, AVRPART * p)
   return 0;
 }
 
+static uint8_t get_fuse_bitmask(AVRMEM * m) {
+  uint8_t bitmask_r = 0;
+  uint8_t bitmask_w = 0;
+  int i;
+
+  if (!m || m->size > 1) {
+    // not a fuse, compare bytes directly
+    return 0xFF;
+  }
+
+  // For fuses, only compare bytes that are actually written *and* read.
+  for (i = 0; i < 32; i++) {
+    if (m->op[AVR_OP_WRITE]->bit[i].type == AVR_CMDBIT_INPUT)
+      bitmask_w |= (1 << m->op[AVR_OP_WRITE]->bit[i].bitno);
+    if (m->op[AVR_OP_READ]->bit[i].type == AVR_CMDBIT_OUTPUT)
+      bitmask_r |= (1 << m->op[AVR_OP_READ]->bit[i].bitno);
+  }
+  return bitmask_r & bitmask_w;
+}
+
+int compare_memory_masked(AVRMEM * m, uint8_t b1, uint8_t b2) {
+  uint8_t bitmask = get_fuse_bitmask(m);
+  return (b1 & bitmask) != (b2 & bitmask);
+}
 
 /*
  * Verify the memory buffer of p with that of v.  The byte range of v,
@@ -1109,11 +1133,30 @@ int avr_verify(AVRPART * p, AVRPART * v, char * memtype, int size)
   for (i=0; i<size; i++) {
     if ((b->tags[i] & TAG_ALLOCATED) != 0 &&
         buf1[i] != buf2[i]) {
-      avrdude_message(MSG_INFO, "%s: verification error, first mismatch at byte 0x%04x\n"
-                      "%s0x%02x != 0x%02x\n",
-                      progname, i,
-                      progbuf, buf1[i], buf2[i]);
-      return -1;
+      uint8_t bitmask = get_fuse_bitmask(a);
+      if((buf1[i] & bitmask) != (buf2[i] & bitmask)) {
+        // Mismatch is not just in unused bits
+        avrdude_message(MSG_INFO, "%s: verification error, first mismatch at byte 0x%04x\n"
+                        "%s0x%02x != 0x%02x\n",
+                        progname, i,
+                        progbuf, buf1[i], buf2[i]);
+        return -1;
+      } else {
+        // Mismatch is only in unused bits
+        if ((buf1[i] | bitmask) != 0xff) {
+          // Programmer returned unused bits as 0, must be the part/programmer
+          avrdude_message(MSG_INFO, "%s: WARNING: ignoring mismatch in unused bits of \"%s\"\n"
+                          "%s(0x%02x != 0x%02x). To prevent this warning fix the part\n"
+                          "%sor programmer definition in the config file.\n",
+                          progname, memtype, progbuf, buf1[i], buf2[i], progbuf);
+        } else {
+          // Programmer returned unused bits as 1, must be the user
+          avrdude_message(MSG_INFO, "%s: WARNING: ignoring mismatch in unused bits of \"%s\"\n"
+                          "%s(0x%02x != 0x%02x). To prevent this warning set unused bits\n"
+                          "%sto 1 when writing (double check with your datasheet first).\n",
+                          progname, memtype, progbuf, buf1[i], buf2[i], progbuf);
+        }
+      }
     }
   }
 
diff --git a/libavrdude.h b/libavrdude.h
index b80ad797..1f0b7fcd 100644
--- a/libavrdude.h
+++ b/libavrdude.h
@@ -33,11 +33,7 @@
 #include <stdint.h>
 typedef uint32_t pinmask_t;
 #else
-#if UINT_MAX >= 0xFFFFFFFF
-typedef unsigned int pinmask_t;
-#else
-typedef unsigned long pinmask_t;
-#endif
+#error Need a C99 capable compiler
 #endif
 
 
@@ -342,6 +338,9 @@ typedef void (*walk_avrparts_cb)(const char *name, const char *desc,
                                  void *cookie);
 void walk_avrparts(LISTID avrparts, walk_avrparts_cb cb, void *cookie);
 void sort_avrparts(LISTID avrparts);
+
+int compare_memory_masked(AVRMEM * m, uint8_t buf1, uint8_t buf2);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/main.c b/main.c
index aa91ae16..0dd9d7ad 100644
--- a/main.c
+++ b/main.c
@@ -1300,8 +1300,11 @@ int main(int argc, char * argv [])
       }
     }
     
+    AVRMEM * m;
+    
     /* Now check what fuses are against what they should be */
-    if (safemodeafter_fuse != safemode_fuse) {
+    m = avr_locate_mem(p, "fuse");
+    if (compare_memory_masked(m, safemodeafter_fuse, safemode_fuse)) {
       fuses_updated = 1;
       avrdude_message(MSG_INFO, "%s: safemode: fuse changed! Was %x, and is now %x\n",
               progname, safemode_fuse, safemodeafter_fuse);
@@ -1329,7 +1332,8 @@ int main(int argc, char * argv [])
     }
 
     /* Now check what fuses are against what they should be */
-    if (safemodeafter_lfuse != safemode_lfuse) {
+    m = avr_locate_mem(p, "lfuse");
+    if (compare_memory_masked(m, safemodeafter_lfuse, safemode_lfuse)) {
       fuses_updated = 1;
       avrdude_message(MSG_INFO, "%s: safemode: lfuse changed! Was %x, and is now %x\n",
               progname, safemode_lfuse, safemodeafter_lfuse);
@@ -1357,7 +1361,8 @@ int main(int argc, char * argv [])
     }
 
     /* Now check what fuses are against what they should be */
-    if (safemodeafter_hfuse != safemode_hfuse) {
+    m = avr_locate_mem(p, "hfuse");
+    if (compare_memory_masked(m, safemodeafter_hfuse, safemode_hfuse)) {
       fuses_updated = 1;
       avrdude_message(MSG_INFO, "%s: safemode: hfuse changed! Was %x, and is now %x\n",
               progname, safemode_hfuse, safemodeafter_hfuse);
@@ -1382,7 +1387,8 @@ int main(int argc, char * argv [])
     }
 
     /* Now check what fuses are against what they should be */
-    if (safemodeafter_efuse != safemode_efuse) {
+    m = avr_locate_mem(p, "efuse");
+    if (compare_memory_masked(m, safemodeafter_efuse, safemode_efuse)) {
       fuses_updated = 1;
       avrdude_message(MSG_INFO, "%s: safemode: efuse changed! Was %x, and is now %x\n",
               progname, safemode_efuse, safemodeafter_efuse);
@@ -1410,7 +1416,7 @@ int main(int argc, char * argv [])
       avrdude_message(MSG_INFO, "%s: safemode: ", progname);
       if (failures == 0) {
         avrdude_message(MSG_INFO, "Fuses OK (E:%02X, H:%02X, L:%02X)\n",
-                safemode_efuse, safemode_hfuse, safemode_lfuse);
+                safemodeafter_efuse, safemodeafter_hfuse, safemodeafter_lfuse);
       }
       else {
         avrdude_message(MSG_INFO, "Fuses not recovered, sorry\n");