diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
index 57cd91e2869f93e617599fd14b7e728252b0279d..92746a9b137c067583b5356ad6ccec5179267082 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
@@ -1174,10 +1174,11 @@ void pf_ul(module_id_t module_id,
     const uint16_t bwpSize = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE);
     NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch;
     NR_pusch_semi_static_t *ps = &sched_ctrl->pusch_semi_static;
+    const NR_mac_dir_stats_t *stats = &UE_info->mac_stats[UE_id].ul;
 
     /* Calculate throughput */
     const float a = 0.0005f; // corresponds to 200ms window
-    const uint32_t b = UE_info->mac_stats[UE_id].ul.current_bytes;
+    const uint32_t b = stats->current_bytes;
     ul_thr_ue[UE_id] = (1 - a) * ul_thr_ue[UE_id] + a * b;
 
     /* Check if retransmission is necessary */
@@ -1209,6 +1210,10 @@ void pf_ul(module_id_t module_id,
       continue;
     }
 
+    const NR_bler_options_t *bo = &nrmac->ul_bler;
+    const int max_mcs = bo->max_mcs; /* no per-user maximum MCS yet */
+    sched_pusch->mcs = get_mcs_from_bler(bo, stats, &sched_ctrl->ul_bler_stats, max_mcs, frame);
+
     /* Schedule UE on SR or UL inactivity and no data (otherwise, will be scheduled
      * based on data to transmit) */
     if (B == 0 && do_sched) {
@@ -1284,7 +1289,7 @@ void pf_ul(module_id_t module_id,
                          sched_ctrl->aggregation_level);
 
       NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch;
-      sched_pusch->mcs = nrmac->min_grant_mcs;
+      sched_pusch->mcs = min(nrmac->min_grant_mcs, sched_pusch->mcs);
       update_ul_ue_R_Qm(sched_pusch, ps);
       sched_pusch->rbStart = rbStart;
       sched_pusch->rbSize = min_rb;
@@ -1310,7 +1315,6 @@ void pf_ul(module_id_t module_id,
     add_tail_nr_list(&UE_sched, UE_id);
 
     /* Calculate coefficient*/
-    sched_pusch->mcs = nrmac->min_grant_mcs;
     const uint32_t tbs = ul_pf_tbs[ps->mcs_table][sched_pusch->mcs];
     coeff_ue[UE_id] = (float) tbs / ul_thr_ue[UE_id];
     LOG_D(NR_MAC,"b %d, ul_thr_ue[%d] %f, tbs %d, coeff_ue[%d] %f\n",
diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c
index b813063e7c1b748d599661377765803cf0b58d97..4c14233a32ad9a658b1850db8713f4e063af8f51 100644
--- a/openair2/LAYER2/NR_MAC_gNB/main.c
+++ b/openair2/LAYER2/NR_MAC_gNB/main.c
@@ -113,12 +113,14 @@ void dump_mac_stats(gNB_MAC_INST *gNB, char *output, int strlen, bool reset_rsrp
       stats->cumul_rsrp = 0;
     }
     stroff+=sprintf(output+stroff,"UE %d: dlsch_total_bytes %"PRIu64"\n", UE_id, stats->dl.total_bytes);
-    stroff+=sprintf(output+stroff,"UE %d: ulsch_rounds %"PRIu64"/%"PRIu64"/%"PRIu64"/%"PRIu64", ulsch_DTX %d, ulsch_errors %"PRIu64"\n",
+    stroff+=sprintf(output+stroff,"UE %d: ulsch_rounds %"PRIu64"/%"PRIu64"/%"PRIu64"/%"PRIu64", ulsch_DTX %d, ulsch_errors %"PRIu64", BLER %.5f MCS %d\n",
                     UE_id,
                     stats->ul.rounds[0], stats->ul.rounds[1],
                     stats->ul.rounds[2], stats->ul.rounds[3],
                     stats->ulsch_DTX,
-                    stats->ul.errors);
+                    stats->ul.errors,
+                    sched_ctrl->ul_bler_stats.bler,
+                    sched_ctrl->ul_bler_stats.mcs);
     stroff+=sprintf(output+stroff,
                     "UE %d: ulsch_total_bytes_scheduled %"PRIu64", ulsch_total_bytes_received %"PRIu64"\n",
                     UE_id,
diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
index 8e72447351d8532a29ff0541512da53dfbca5439..99095e1dede3e0a64f6132b56e4c59f15862dd5a 100644
--- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
+++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
@@ -627,6 +627,7 @@ typedef struct {
 
   /// Estimation of HARQ from BLER
   NR_bler_stats_t dl_bler_stats;
+  NR_bler_stats_t ul_bler_stats;
 
   uint16_t ta_frame;
   int16_t ta_update;